add redirects on login

This commit is contained in:
b1ek 2023-05-17 01:08:04 +10:00
parent bac279ae9e
commit d35b50ad70
Signed by: blek
GPG Key ID: 14546221E3595D0C
6 changed files with 142 additions and 29 deletions

View File

@ -131,7 +131,7 @@ class PsychTestAnswers(models.Model):
verbose_name = "Ответ на психологический тест"
verbose_name_plural = "Ответы на психологический тест"
class AuthTokens(models.Model):
class AuthToken(models.Model):
user = models.BigIntegerField(null=False, verbose_name='ID Пользователя, которому принадлежит токен');
key = models.TextField(verbose_name='Ключ API');
expires = models.BigIntegerField(verbose_name='Когда ключ истечет (Unix timestamp)');

View File

@ -1,6 +1,6 @@
from rest_framework import serializers
from .models import Apartament, User
from .models import Apartament, User, AuthToken
class ApartamentListSerializer(serializers.ModelSerializer):
@ -26,4 +26,9 @@ class PsychTestAddResultSerializer(serializers.ModelSerializer):
class PublicUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
exclude = ('favorites_apartments', 'comparison_apartments')
exclude = ('favorites_apartments', 'comparison_apartments')
class TokenSerializer(serializers.ModelSerializer):
class Meta:
model = AuthToken
fields = '__all__'

View File

@ -10,13 +10,15 @@ from django.db.models.query import QuerySet
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
from .models import Apartament, User, PsychTestAnswers
from .models import Apartament, User, PsychTestAnswers, AuthToken
from .serializer import (ApartamentListSerializer,
ApartamentDetailSerializer,
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):
"""Вывод списка квартир или отдельной квартиры"""
@ -185,7 +187,7 @@ def register(oid, provider_id, name):
# discord=,
# city=,
role='s',
# photo_provider=,
photo_provider='VVSU',
openid_addr=oid,
openid_id=provider_id,
);
@ -206,7 +208,45 @@ def get_oauth_data(remote, key):
'User-Agent': 'curl/8.1'
}).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):
# TODO: Remove csrf exempt when index.html is loaded through django
@csrf_exempt
def post(self, req: HttpRequest):
@ -227,18 +267,14 @@ class UserLogin(APIView):
res.status_code = 400;
return res;
# auth_data = get_oauth_token('https://vvsu.ru/connect', {
# 'grant_type': 'authorization_code',
# 'redirect_uri': 'https://pairent.vvsu.ru/sign-in/',
# 'code': data['code'],
# 'code_verifier': data['code_verifier'],
# 'client_id': 'it-hub-client',
# '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);
auth_data = get_oauth_token('https://vvsu.ru/connect', {
'grant_type': 'authorization_code',
'redirect_uri': 'https://pairent.vvsu.ru/sign-in/',
'code': data['code'],
'code_verifier': data['code_verifier'],
'client_id': 'it-hub-client',
'client_secret': 'U8y@uPVee6Q^*729esHTo4Vd'
});
if ('error' in auth_data):
return JsonResponse(auth_data);
@ -246,16 +282,13 @@ class UserLogin(APIView):
user = None;
new_user = False;
# 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__'}
vvsu_data = get_oauth_data('https://vvsu.ru/connect', auth_data['access_token']);
if ('error' in vvsu_data):
res = JsonResponse(vvsu_data);
res.status_code = 500;
return res;
req.session['auth_data'] = vvsu_data;
if ('error' in vvsu_data):
res = JsonResponse(vvsu_data);
res.status_code = 500;
@ -270,7 +303,8 @@ class UserLogin(APIView):
return JsonResponse({
'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):

View File

@ -4,4 +4,4 @@ djangorestframework
django-cors-headers
Pillow
requests
oidc-client
python-ipware

View File

@ -14,7 +14,70 @@ class UserLoginResponse {
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) {
for (const key in data) {
this[key] = data[key];
@ -44,7 +107,11 @@ class User {
}
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;
}
}

View File

@ -4,6 +4,7 @@ import { HashLoader } from "react-spinners";
import { SigninResponse, UserManager } from 'oidc-client-ts';
import { User } from "../../API/User";
import FloatingBox from "../../components/UI/FloatingBox";
import { useNavigate } from "react-router-dom";
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() {