finish off login

This commit is contained in:
b1ek 2023-05-17 02:10:17 +10:00
parent 754bfa8ef0
commit 601b13feb6
Signed by: blek
GPG Key ID: 14546221E3595D0C
4 changed files with 71 additions and 20 deletions

View File

@ -251,6 +251,9 @@ class UserLogin(APIView):
@csrf_exempt @csrf_exempt
def post(self, req: HttpRequest): def post(self, req: HttpRequest):
# for debug purposes
# return HttpResponse("""{"user_data": {"id": 1, "name": "\u041d\u0438\u043a\u0438\u0442\u0430 \u041f\u0443\u0441\u0442\u043e\u0432\u0430\u043b\u043e\u0432", "date_of_birth": null, "about_me": "", "gender": "?", "phone": "+00000", "email": null, "telegram": null, "discord": null, "city": null, "role": "s", "photo_provider": "VVSU", "openid_addr": "blek__@vvsu.ru", "openid_id": "096C78CD-4943-4D57-BC6D-5CDE12F686E3"}, "new_user": false, "token": {"id": 2, "user": 1, "key": "e1c24581-523a-4f60-973f-02ba873b3edc", "expires": 1684423572, "ip": "127.0.0.1"}}""");
if (req.session.has_key('auth_data')): if (req.session.has_key('auth_data')):
# TODO: Return user object instead of error # TODO: Return user object instead of error
return JsonResponse({'error': 'already authenticated'}) return JsonResponse({'error': 'already authenticated'})

View File

@ -21,30 +21,44 @@ class IAPIObject {
*/ */
static storage_key = undefined; static storage_key = undefined;
/** @returns {ThisType} */ static _checkStorageSupport() {
static restoreFromLocalStorage() { if (storage_key === undefined) {
if (storage_key !== undefined) {
throw Error('This doesn\'t support local storage'); throw Error('This doesn\'t support local storage');
} }
}
_getStorageKey() {
return Object.getPrototypeOf(this).constructor.storage_key;
}
_IcheckStorageSupport() {
if (this._getStorageKey() === undefined) {
throw Error('This doesn\'t support local storage');
}
}
/** @returns {ThisType} */
static restoreFromLocalStorage() {
_checkStorageSupport();
if (!window.localStorage.getItem(storage_key)) if (!window.localStorage.getItem(storage_key))
return false; return false;
return new APIToken(window.localStorage.getItem(storage_key)); return new APIToken(window.localStorage.getItem(storage_key));
} }
/** @returns {boolean} */
static isCached() {
_checkStorageSupport();
}
/** /**
* Save this object to local storage * Save this object to local storage
* @throws {QuotaExceededError} * @throws {QuotaExceededError}
* @returns {void} * @returns {void}
*/ */
saveToLocalStorage() { saveToLocalStorage() {
this._IcheckStorageSupport();
// static this window.localStorage.setItem(this._getStorageKey(), JSON.stringify(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);
} }
} }
@ -53,6 +67,7 @@ class APIToken extends IAPIObject {
static storage_key = 'pairent_api_key'; static storage_key = 'pairent_api_key';
constructor(data) { constructor(data) {
super();
this.user = data.user; this.user = data.user;
this.key = data.key; this.key = data.key;
this.expires = data.expires; this.expires = data.expires;
@ -76,9 +91,14 @@ class APIToken extends IAPIObject {
class User extends IAPIObject { class User extends IAPIObject {
isLoggedIn() {
return false;
}
static storage_key = 'pairent_user_data'; static storage_key = 'pairent_user_data';
constructor(data) { constructor(data) {
super();
for (const key in data) { for (const key in data) {
this[key] = data[key]; this[key] = data[key];
} }
@ -107,9 +127,14 @@ class User extends IAPIObject {
} }
const data = await axios.post(api_path('/api/auth/user/login'), response); const data = await axios.post(api_path('/api/auth/user/login'), response);
if (data.status !== 200) {
return false;
}
window.localStorage.setItem(APIToken.storage_key, data.data.token); if (!data.data.error) {
window.localStorage.setItem(User.storage_key, data.data.user_data); new APIToken(data.data.token).saveToLocalStorage();
new User(data.data.user_data).saveToLocalStorage();
}
return data.data; return data.data;
} }

View File

@ -4,7 +4,6 @@ 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";
@ -33,12 +32,12 @@ export default class LoggedIn extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.response = new SigninResponse(new URL(window.location.href).searchParams); this.response = new SigninResponse(new URL(window.location.href).searchParams);
} }
async componentDidMount() { async componentDidMount() {
if (this.response.error) return; if (this.response.error) return;
window.localStorage.removeItem('auth_fail');
let code_verifier = '?'; let code_verifier = '?';
// get code verifier // get code verifier
for (const key in localStorage) { for (const key in localStorage) {
@ -50,11 +49,19 @@ export default class LoggedIn extends React.Component {
} }
const response = await User.login({...this.response, code_verifier}); const response = await User.login({...this.response, code_verifier});
if (response.error) {
// pass the data to LoginPage
window.localStorage.setItem('auth_fail', JSON.stringify(response));
window.location.href = '/login';
return;
}
if (response.new_user) { if (response.new_user) {
// TODO: Make the page // TODO: Make the page
useNavigate('/register'); window.location.href = '/register';
} else { } else {
useNavigate('/'); window.location.href = '/';
} }
} }

View File

@ -45,9 +45,11 @@ export default class LoginPage extends React.Component {
super(props); super(props);
this.state = { this.state = {
loading: false loading: false,
error: JSON.parse(window.localStorage.getItem('auth_fail'))
} }
window.localStorage.removeItem('auth_fail');
this.openid = this.openid.bind(this); this.openid = this.openid.bind(this);
} }
@ -56,12 +58,11 @@ export default class LoginPage extends React.Component {
this.setState({loading: true}); this.setState({loading: true});
OpenID.Log.setLogger(console); OpenID.Log.setLogger(console);
OpenID.Log.setLevel(OpenID.Log.DEBUG); OpenID.Log.setLevel(OpenID.Log.NONE);
let client = new OpenID.UserManager(OIDCConfig); let client = new OpenID.UserManager(OIDCConfig);
client.signinRedirect(); client.signinRedirect();
} }
render() { render() {
@ -84,6 +85,21 @@ export default class LoginPage extends React.Component {
Вход осуществляется только через<br/> Вход осуществляется только через<br/>
Систему Единого Входа ВВГУ Систему Единого Входа ВВГУ
</SmallText> </SmallText>
{
this.state.error ?
<SmallText style={{color: 'darkred', fontWeight: '600'}}>
Произошла ошибка: { this.state.error.error }
{
this.state.error.error_description ?
<>
<br/>
{this.state.error.error_description}
</>
: null
}
</SmallText>
: null
}
</FloatingBox> </FloatingBox>
</div> </div>
); );