add redirects on login
This commit is contained in:
parent
bac279ae9e
commit
d35b50ad70
|
@ -131,7 +131,7 @@ class PsychTestAnswers(models.Model):
|
||||||
verbose_name = "Ответ на психологический тест"
|
verbose_name = "Ответ на психологический тест"
|
||||||
verbose_name_plural = "Ответы на психологический тест"
|
verbose_name_plural = "Ответы на психологический тест"
|
||||||
|
|
||||||
class AuthTokens(models.Model):
|
class AuthToken(models.Model):
|
||||||
user = models.BigIntegerField(null=False, verbose_name='ID Пользователя, которому принадлежит токен');
|
user = models.BigIntegerField(null=False, verbose_name='ID Пользователя, которому принадлежит токен');
|
||||||
key = models.TextField(verbose_name='Ключ API');
|
key = models.TextField(verbose_name='Ключ API');
|
||||||
expires = models.BigIntegerField(verbose_name='Когда ключ истечет (Unix timestamp)');
|
expires = models.BigIntegerField(verbose_name='Когда ключ истечет (Unix timestamp)');
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from .models import Apartament, User
|
from .models import Apartament, User, AuthToken
|
||||||
|
|
||||||
|
|
||||||
class ApartamentListSerializer(serializers.ModelSerializer):
|
class ApartamentListSerializer(serializers.ModelSerializer):
|
||||||
|
@ -27,3 +27,8 @@ class PublicUserSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
exclude = ('favorites_apartments', 'comparison_apartments')
|
exclude = ('favorites_apartments', 'comparison_apartments')
|
||||||
|
|
||||||
|
class TokenSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = AuthToken
|
||||||
|
fields = '__all__'
|
|
@ -10,13 +10,15 @@ from django.db.models.query import QuerySet
|
||||||
from django.core.validators import validate_email
|
from django.core.validators import validate_email
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from .models import Apartament, User, PsychTestAnswers
|
from .models import Apartament, User, PsychTestAnswers, AuthToken
|
||||||
from .serializer import (ApartamentListSerializer,
|
from .serializer import (ApartamentListSerializer,
|
||||||
ApartamentDetailSerializer,
|
ApartamentDetailSerializer,
|
||||||
PsychTestAddResultSerializer,
|
PsychTestAddResultSerializer,
|
||||||
PublicUserSerializer)
|
PublicUserSerializer,
|
||||||
|
TokenSerializer)
|
||||||
|
|
||||||
import json, math, random, re, requests, oidc_client, base64, hashlib
|
import json, math, random, re, requests, oidc_client, base64, uuid, time, ipware as iplib
|
||||||
|
ipware = iplib.IpWare();
|
||||||
|
|
||||||
class ApartamentViewSet(viewsets.ReadOnlyModelViewSet):
|
class ApartamentViewSet(viewsets.ReadOnlyModelViewSet):
|
||||||
"""Вывод списка квартир или отдельной квартиры"""
|
"""Вывод списка квартир или отдельной квартиры"""
|
||||||
|
@ -185,7 +187,7 @@ def register(oid, provider_id, name):
|
||||||
# discord=,
|
# discord=,
|
||||||
# city=,
|
# city=,
|
||||||
role='s',
|
role='s',
|
||||||
# photo_provider=,
|
photo_provider='VVSU',
|
||||||
openid_addr=oid,
|
openid_addr=oid,
|
||||||
openid_id=provider_id,
|
openid_id=provider_id,
|
||||||
);
|
);
|
||||||
|
@ -206,7 +208,45 @@ def get_oauth_data(remote, key):
|
||||||
'User-Agent': 'curl/8.1'
|
'User-Agent': 'curl/8.1'
|
||||||
}).json();
|
}).json();
|
||||||
|
|
||||||
|
def create_auth_token(userid, ip):
|
||||||
|
|
||||||
|
try:
|
||||||
|
token = AuthToken.objects.get(user=userid, ip=ip);
|
||||||
|
if (verify_auth_token(token.key, token.ip)):
|
||||||
|
return token;
|
||||||
|
except AuthToken.DoesNotExist:
|
||||||
|
0 # ignore
|
||||||
|
|
||||||
|
token = AuthToken(
|
||||||
|
user=userid,
|
||||||
|
key=str(uuid.uuid4()),
|
||||||
|
# 2 days
|
||||||
|
# vvv
|
||||||
|
expires=time.time() + 60 * 60 * 24 * 2,
|
||||||
|
ip=ip
|
||||||
|
);
|
||||||
|
token.save();
|
||||||
|
return token;
|
||||||
|
|
||||||
|
def verify_auth_token(key, ip):
|
||||||
|
|
||||||
|
try:
|
||||||
|
token = AuthToken.objects.get(key=key);
|
||||||
|
except AuthToken.DoesNotExist:
|
||||||
|
return False;
|
||||||
|
|
||||||
|
if (token.ip != ip):
|
||||||
|
token.delete();
|
||||||
|
return False;
|
||||||
|
|
||||||
|
if (token.expires > time.time()):
|
||||||
|
token.delete();
|
||||||
|
return False;
|
||||||
|
|
||||||
|
return True;
|
||||||
|
|
||||||
class UserLogin(APIView):
|
class UserLogin(APIView):
|
||||||
|
|
||||||
# TODO: Remove csrf exempt when index.html is loaded through django
|
# TODO: Remove csrf exempt when index.html is loaded through django
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def post(self, req: HttpRequest):
|
def post(self, req: HttpRequest):
|
||||||
|
@ -227,18 +267,14 @@ class UserLogin(APIView):
|
||||||
res.status_code = 400;
|
res.status_code = 400;
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
# auth_data = get_oauth_token('https://vvsu.ru/connect', {
|
auth_data = get_oauth_token('https://vvsu.ru/connect', {
|
||||||
# 'grant_type': 'authorization_code',
|
'grant_type': 'authorization_code',
|
||||||
# 'redirect_uri': 'https://pairent.vvsu.ru/sign-in/',
|
'redirect_uri': 'https://pairent.vvsu.ru/sign-in/',
|
||||||
# 'code': data['code'],
|
'code': data['code'],
|
||||||
# 'code_verifier': data['code_verifier'],
|
'code_verifier': data['code_verifier'],
|
||||||
# 'client_id': 'it-hub-client',
|
'client_id': 'it-hub-client',
|
||||||
# 'client_secret': 'U8y@uPVee6Q^*729esHTo4Vd'
|
'client_secret': 'U8y@uPVee6Q^*729esHTo4Vd'
|
||||||
# });
|
});
|
||||||
|
|
||||||
auth_data = {'access_token': 'gcH96CSYQBeiq9te1lpJV4T9mBH4UabT4_m6fJQFQK4.K4GA7sXFtBEM26kDladZjZ8phsI3aRPmqu5oRts4Csg', 'expires_in': 3600, 'id_token': 'eyJhbGciOiJSUzI1NiIsImtpZCI6InB1YmxpYzpoeWRyYS5vcGVuaWQuaWQtdG9rZW4iLCJ0eXAiOiJKV1QifQ.eyJhY3IiOiIwIiwiYXRfaGFzaCI6ImJIZS1pWmlvX2Npa3diOFc3bnBkbEEiLCJhdWQiOlsiaXQtaHViLWNsaWVudCJdLCJhdXRoX3RpbWUiOjE2ODQyNDM0NjUsImNhbGxiYWNrX3VybCI6IiIsImV4cCI6MTY4NDI0NzA3MywiZmFtaWx5X25hbWUiOiLQn9GD0YHRgtC-0LLQsNC70L7QsiIsImdpdmVuX25hbWUiOiLQndC40LrQuNGC0LAiLCJpYXQiOjE2ODQyNDM0NzMsImlkIjoiMDk2Qzc4Q0QtNDk0My00RDU3LUJDNkQtNUNERTEyRjY4NkUzIiwiaXNzIjoiaHR0cHM6Ly93d3cudnZzdS5ydS9jb25uZWN0LyIsImp0aSI6IjU5M2FiYTQzLTU4OTQtNGZmNy1iMmU1LTdmOWZkYTZjZjFhZSIsImxvZ2luIjoiaHR0cHM6Ly9vcGVuaWQudnZzdS5ydS9ibGVrX18iLCJvcGVuaWQiOiJodHRwczovL29wZW5pZC52dnN1LnJ1L2JsZWtfXyIsInBpY3R1cmUiOiJodHRwczovL3d3dy52dnN1LnJ1L29pc2twL3Bob3RvL3B0aC5hc3A_SUQ9MDk2Qzc4Q0QtNDk0My00RDU3LUJDNkQtNUNERTEyRjY4NkUzXHUwMDI2IiwicHJvZmlsZV91cmwiOm51bGwsInJhdCI6MTY4NDI0MzQ1NCwic2lkIjoiMzEwZjU5MWEtZmNjYy00NzY3LTkzMmItYjM3OTQyZmFmMTA1Iiwic3ViIjoiaHR0cHM6Ly9vcGVuaWQudnZzdS5ydS9ibGVrX18iLCJzdXJuYW1lIjoi0J_Rg9GB0YLQvtCy0LDQu9C-0LIiLCJ0aXRsZSI6ItCh0YLRg9C00LXQvdGCIiwidnZzdV9JZEVtcGwiOm51bGwsInZ2c3VfSWRTdHVkIjoiMTk3MDgwIiwidnZzdV9JZFVzZXIiOjE5MDQ4OSwidnZzdV9sb2dpbiI6ImJsZWtfXyJ9.mClShf1lzGoKarsshafM6H2_57wrINbLSUjDQrEOAICN0V6TMNmC2zevgjxBbMl3BTIWhGJ37SNViyGvdNjPeG_S32TBr0m_vJEddZbHLzO7U7J2vqYVkiFQl8hziZkvhZUboSCu71aWexvN6rtX5grxIPAZswgGP4Mszg7ueQlhybgDELVg-UG-2OVH01-ynsfoZbaPYN6_8x44FJDUiltFbdx57kD8OEh4CdqEPTl3rL2T1U04cfNY0Ij2ivo9esEyAmuuXQCmwn_YwHO3TQc0S2Bq6DeIWa4gauynxGjPl2tf4fcyz-XOVWGeMNIwXCHvIDB_aHsZromG3UV2gY3ji-RlkEq81mYzFjOwB-LArkJQ68zQZlu5cFKqtWvZOzKqCzDDRUvfiRTu3OexQse_g10EeMi7vSeocGnfETlq5utar05gFGY-DxSaFYNCKzxqqS8V78d5aRFrWcQNbE6CVpKZPbZBBEQ-ItX-wh1FEyL3Uw-MsDztwJu6p_ftwRZLF0lk3ECFlbFt4NzzutFYqwS1s5ZoSZa-ylLY8PsZdr9gj58jBYD8c1foXZ9I_KzC_bYDOyUQfjec5njxGWN3828TvySclHkXMUgQxCM16OmPq8MICk_tfhqOSezcs0JpXIEtHHn0h9HNavZuhMTIaTWErYRIIxEPgtBn8r8', 'scope': 'openid vvsu_IdUser vvsu_IdEmpl vvsu_IdStud vvsu_login given_name family_name', 'token_type': 'bearer'}
|
|
||||||
|
|
||||||
# print(auth_data);
|
|
||||||
|
|
||||||
if ('error' in auth_data):
|
if ('error' in auth_data):
|
||||||
return JsonResponse(auth_data);
|
return JsonResponse(auth_data);
|
||||||
|
@ -246,16 +282,13 @@ class UserLogin(APIView):
|
||||||
user = None;
|
user = None;
|
||||||
new_user = False;
|
new_user = False;
|
||||||
|
|
||||||
# vvsu_data = get_oauth_data('https://vvsu.ru/connect', auth_data['access_token']);
|
vvsu_data = get_oauth_data('https://vvsu.ru/connect', auth_data['access_token']);
|
||||||
vvsu_data = {'acr': '0', 'aud': ['it-hub-client'], 'auth_time': 1684243465, 'callback_url': '', 'family_name': 'Пустовалов', 'given_name': 'Никита', 'iat': 1684243466, 'id': '096C78CD-4943-4D57-BC6D-5CDE12F686E3', 'iss': 'https://www.vvsu.ru/connect/', 'login': 'https://openid.vvsu.ru/blek__', 'openid': 'https://openid.vvsu.ru/blek__', 'picture': 'https://www.vvsu.ru/oiskp/photo/pth.asp?ID=096C78CD-4943-4D57-BC6D-5CDE12F686E3&', 'profile_url': None, 'rat': 1684243454, 'sub': 'https://openid.vvsu.ru/blek__', 'surname': 'Пустовалов', 'title': 'Студент', 'vvsu_IdEmpl': None, 'vvsu_IdStud': '197080', 'vvsu_IdUser': 190489, 'vvsu_login': 'blek__'}
|
|
||||||
|
|
||||||
if ('error' in vvsu_data):
|
if ('error' in vvsu_data):
|
||||||
res = JsonResponse(vvsu_data);
|
res = JsonResponse(vvsu_data);
|
||||||
res.status_code = 500;
|
res.status_code = 500;
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
req.session['auth_data'] = vvsu_data;
|
|
||||||
|
|
||||||
if ('error' in vvsu_data):
|
if ('error' in vvsu_data):
|
||||||
res = JsonResponse(vvsu_data);
|
res = JsonResponse(vvsu_data);
|
||||||
res.status_code = 500;
|
res.status_code = 500;
|
||||||
|
@ -270,7 +303,8 @@ class UserLogin(APIView):
|
||||||
|
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
'user_data': PublicUserSerializer(user).data,
|
'user_data': PublicUserSerializer(user).data,
|
||||||
'new_user': new_user
|
'new_user': new_user,
|
||||||
|
'token': TokenSerializer(create_auth_token(user.id, ipware.get_client_ip(req.META)[0].exploded)).data
|
||||||
});
|
});
|
||||||
|
|
||||||
class UserGet(APIView):
|
class UserGet(APIView):
|
||||||
|
|
|
@ -4,4 +4,4 @@ djangorestframework
|
||||||
django-cors-headers
|
django-cors-headers
|
||||||
Pillow
|
Pillow
|
||||||
requests
|
requests
|
||||||
oidc-client
|
python-ipware
|
|
@ -14,7 +14,70 @@ class UserLoginResponse {
|
||||||
id;
|
id;
|
||||||
}
|
}
|
||||||
|
|
||||||
class User {
|
class IAPIObject {
|
||||||
|
/**
|
||||||
|
* Local storage key used to save data.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
static storage_key = undefined;
|
||||||
|
|
||||||
|
/** @returns {ThisType} */
|
||||||
|
static restoreFromLocalStorage() {
|
||||||
|
if (storage_key !== undefined) {
|
||||||
|
throw Error('This doesn\'t support local storage');
|
||||||
|
}
|
||||||
|
if (!window.localStorage.getItem(storage_key))
|
||||||
|
return false;
|
||||||
|
return new APIToken(window.localStorage.getItem(storage_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save this object to local storage
|
||||||
|
* @throws {QuotaExceededError}
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
saveToLocalStorage() {
|
||||||
|
|
||||||
|
// static this
|
||||||
|
sthis = Object.getPrototypeOf(this);
|
||||||
|
|
||||||
|
if (sthis.storage_key !== undefined) {
|
||||||
|
throw Error('This doesn\'t support local storage');
|
||||||
|
}
|
||||||
|
window.localStorage.setItem(sthis.storage_key, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class APIToken extends IAPIObject {
|
||||||
|
|
||||||
|
static storage_key = 'pairent_api_key';
|
||||||
|
|
||||||
|
constructor(data) {
|
||||||
|
this.user = data.user;
|
||||||
|
this.key = data.key;
|
||||||
|
this.expires = data.expires;
|
||||||
|
this.ip = data.ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {number} */
|
||||||
|
user;
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
|
key;
|
||||||
|
|
||||||
|
/** A Unix timestamp (when the token will expire)
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
expires;
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
|
ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
class User extends IAPIObject {
|
||||||
|
|
||||||
|
static storage_key = 'pairent_user_data';
|
||||||
|
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
for (const key in data) {
|
for (const key in data) {
|
||||||
this[key] = data[key];
|
this[key] = data[key];
|
||||||
|
@ -44,7 +107,11 @@ class User {
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await axios.post(api_path('/api/auth/user/login'), response);
|
const data = await axios.post(api_path('/api/auth/user/login'), response);
|
||||||
return new User(data.data);
|
|
||||||
|
window.localStorage.setItem(APIToken.storage_key, data.data.token);
|
||||||
|
window.localStorage.setItem(User.storage_key, data.data.user_data);
|
||||||
|
|
||||||
|
return data.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { HashLoader } from "react-spinners";
|
||||||
import { SigninResponse, UserManager } from 'oidc-client-ts';
|
import { SigninResponse, UserManager } from 'oidc-client-ts';
|
||||||
import { User } from "../../API/User";
|
import { User } from "../../API/User";
|
||||||
import FloatingBox from "../../components/UI/FloatingBox";
|
import FloatingBox from "../../components/UI/FloatingBox";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import constants from "../../constants";
|
import constants from "../../constants";
|
||||||
|
|
||||||
|
@ -48,7 +49,13 @@ export default class LoggedIn extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(await User.login({...this.response, code_verifier}));
|
const response = await User.login({...this.response, code_verifier});
|
||||||
|
if (response.new_user) {
|
||||||
|
// TODO: Make the page
|
||||||
|
useNavigate('/register');
|
||||||
|
} else {
|
||||||
|
useNavigate('/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
Loading…
Reference in New Issue