♻️ Simplified Authentication-code
This commit is contained in:
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'));
|
||||
|
||||
Reference in New Issue
Block a user