♻️ 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.config import settings
from classquiz.db import database from classquiz.db import database
from datetime import timedelta 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.routers import users, quiz, utils, stats, storage, search, testing_routes, editor, live, eximport
from classquiz.socket_server import sio from classquiz.socket_server import sio
from classquiz.helpers import meilisearch_init, telemetry_ping, bg_tasks from classquiz.helpers import meilisearch_init, telemetry_ping, bg_tasks
@@ -60,6 +62,11 @@ async def shutdown() -> None:
await database_.disconnect() 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.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(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) 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]: async def __call__(self, request: Request) -> Optional[str]:
authorization: str = request.cookies.get("access_token") # changed to accept access token from httpOnly Cookie 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) scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "bearer": if not authorization or scheme.lower() != "bearer":
if self.auto_error: 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 # 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 # 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/. # 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 from classquiz.oauth import google, github
router = APIRouter() router = APIRouter()
router.include_router(google.router, prefix="/google") router.include_router(google.router, prefix="/google")
router.include_router(github.router, prefix="/github") 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
+7 -29
View File
@@ -9,37 +9,15 @@ import type { Handle } from '@sveltejs/kit';
/** @type {import('@sveltejs/kit').Handle} */ /** @type {import('@sveltejs/kit').Handle} */
export const handle: Handle = async ({ event, resolve }) => { export const handle: Handle = async ({ event, resolve }) => {
const cookies = cookie.parse(event.request.headers.get('cookie') || ''); const res = await fetch(`${process.env.API_URL}/api/v1/users/check`, {
const jwt = /^Bearer (.*)$/gm.exec(cookies.access_token); method: 'GET',
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: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json',
}, Cookie: event.request.headers.get('cookie') || ''
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;
} }
event.locals.email = await ( });
await fetch(`${process.env.API_URL}/api/v1/users/auth/internal/email`, { if (res.ok) {
method: 'POST', event.locals.email = await res.text();
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
jwt: new_jwt
})
})
).text();
const resp = await resolve(event); const resp = await resolve(event);
try { try {
resp.headers.set('Set-Cookie', res.headers.get('set-cookie')); resp.headers.set('Set-Cookie', res.headers.get('set-cookie'));