♻️ Simplified Authentication-code

This commit is contained in:
Mawoka
2022-12-17 16:10:32 +01:00
parent d044745d62
commit bb848adca8
4 changed files with 54 additions and 32 deletions
+7
View File
@@ -12,6 +12,8 @@ from starlette.middleware.sessions import SessionMiddleware
from classquiz.config import settings
from classquiz.db import database
from datetime import timedelta
from classquiz.oauth import rememberme_middleware
from classquiz.routers import users, quiz, utils, stats, storage, search, testing_routes, editor, live, eximport
from classquiz.socket_server import sio
from classquiz.helpers import meilisearch_init, telemetry_ping, bg_tasks
@@ -60,6 +62,11 @@ async def shutdown() -> None:
await database_.disconnect()
@app.middleware("http")
async def auth_middleware_wrapper(request: Request, call_next):
return await rememberme_middleware(request, call_next)
app.add_middleware(SessionMiddleware, secret_key=settings.secret_key)
app.include_router(users.router, tags=["users"], prefix="/api/v1/users", include_in_schema=True)
app.include_router(quiz.router, tags=["quiz"], prefix="/api/v1/quiz", include_in_schema=True)
+5 -1
View File
@@ -44,7 +44,11 @@ class OAuth2PasswordBearerWithCookie(OAuth2):
async def __call__(self, request: Request) -> Optional[str]:
authorization: str = request.cookies.get("access_token") # changed to accept access token from httpOnly Cookie
if authorization is None:
try:
authorization = request.state.access_token
except AttributeError:
pass
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "bearer":
if self.auto_error:
+34 -1
View File
@@ -1,11 +1,44 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
from datetime import timedelta, datetime
from fastapi import APIRouter
from fastapi import APIRouter, Request, Response
from classquiz.auth import ACCESS_TOKEN_EXPIRE_MINUTES, create_access_token
from classquiz.db.models import UserSession
from classquiz.oauth import google, github
router = APIRouter()
router.include_router(google.router, prefix="/google")
router.include_router(github.router, prefix="/github")
async def rememberme_middleware(request: Request, call_next):
rememberme_cookie = request.cookies.get("rememberme_token")
bearer_token = request.cookies.get("access_token")
if rememberme_cookie is not None and bearer_token is None:
user_session: UserSession | None = (
await UserSession.objects.filter(session_key=rememberme_cookie)
.select_related(UserSession.user)
.get_or_none()
)
if (user_session is None) or (user_session.user is None):
response: Response = await call_next(request)
return response
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES * 60)
access_token = create_access_token(data={"sub": user_session.user.email}, expires_delta=access_token_expires)
await user_session.update(last_seen=datetime.now())
request.state.access_token = f"Bearer {access_token}"
response: Response = await call_next(request)
response.set_cookie(
key="access_token",
value=f"Bearer {access_token}",
httponly=True,
samesite="lax",
max_age=ACCESS_TOKEN_EXPIRE_MINUTES * 60,
)
else:
response: Response = await call_next(request)
return response
+8 -30
View File
@@ -9,37 +9,15 @@ import type { Handle } from '@sveltejs/kit';
/** @type {import('@sveltejs/kit').Handle} */
export const handle: Handle = async ({ event, resolve }) => {
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
const jwt = /^Bearer (.*)$/gm.exec(cookies.access_token);
const rememberme_token = cookies.rememberme_token;
if (rememberme_token) {
const res = await fetch(`${process.env.API_URL}/api/v1/users/auth/internal`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
rememberme: rememberme_token,
jwt: jwt === null ? undefined : jwt[0]
})
});
let new_jwt;
if (jwt) {
new_jwt = jwt[0];
} else {
new_jwt = cookie.parse(res.headers.get('set-cookie') ?? '').access_token;
const res = await fetch(`${process.env.API_URL}/api/v1/users/check`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Cookie: event.request.headers.get('cookie') || ''
}
event.locals.email = await (
await fetch(`${process.env.API_URL}/api/v1/users/auth/internal/email`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
jwt: new_jwt
})
})
).text();
});
if (res.ok) {
event.locals.email = await res.text();
const resp = await resolve(event);
try {
resp.headers.set('Set-Cookie', res.headers.get('set-cookie'));