From 272688da26892324e83b4593b2ea51885b043a62 Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Tue, 28 Jul 2020 11:47:20 +0200 Subject: [PATCH] Reduce the amount of SQL requests made for authentication --- src/auth/AuthComponent.ts | 38 ++++++++++++++----------- src/auth/AuthController.ts | 2 +- src/auth/AuthGuard.ts | 58 +++++++++++++++++++++++--------------- 3 files changed, 59 insertions(+), 39 deletions(-) diff --git a/src/auth/AuthComponent.ts b/src/auth/AuthComponent.ts index 0605abf..a80bd63 100644 --- a/src/auth/AuthComponent.ts +++ b/src/auth/AuthComponent.ts @@ -15,14 +15,15 @@ export default class AuthComponent extends ApplicationComponent { public async init(router: Router): Promise { router.use(async (req, res, next) => { req.authGuard = this.authGuard; - res.locals.user = await (await req.authGuard.getProofForSession(req.session!))?.getResource(); + res.locals.user = await (await req.authGuard.getProof(req))?.getResource(); next(); }); } } export const REQUIRE_REQUEST_AUTH_MIDDLEWARE = async (req: Request, res: Response, next: NextFunction): Promise => { - if (!await req.authGuard.isAuthenticatedViaRequest(req)) { + let proof = await req.authGuard.isAuthenticatedViaRequest(req); + if (!proof) { req.flash('error', `You must be logged in to access ${req.url}.`); res.redirect(Controller.route('auth', undefined, { redirect_uri: req.url, @@ -30,26 +31,31 @@ export const REQUIRE_REQUEST_AUTH_MIDDLEWARE = async (req: Request, res: Respons return; } - req.models.user = await (await req.authGuard.getProofForRequest(req))?.getResource(); + req.models.user = await proof.getResource(); next(); }; export const REQUIRE_AUTH_MIDDLEWARE = async (req: Request, res: Response, next: NextFunction): Promise => { - if (await req.authGuard.isAuthenticatedViaRequest(req)) { - req.models.user = await (await req.authGuard.getProofForRequest(req))?.getResource(); - next(); - } else { - if (!await req.authGuard.isAuthenticated(req.session!)) { - req.flash('error', `You must be logged in to access ${req.url}.`); - res.redirect(Controller.route('auth', undefined, { - redirect_uri: req.url, - })); - return; - } - - req.models.user = await (await req.authGuard.getProofForSession(req.session!))?.getResource(); + // Via request + let proof = await req.authGuard.isAuthenticatedViaRequest(req); + if (proof) { + req.models.user = await proof.getResource(); next(); + return; } + + // Via session + proof = await req.authGuard.isAuthenticated(req.session!); + if (!proof) { + req.flash('error', `You must be logged in to access ${req.url}.`); + res.redirect(Controller.route('auth', undefined, { + redirect_uri: req.url, + })); + return; + } + + req.models.user = await proof.getResource(); + next(); }; export const REQUIRE_GUEST_MIDDLEWARE = async (req: Request, res: Response, next: NextFunction): Promise => { if (await req.authGuard.isAuthenticated(req.session!)) { diff --git a/src/auth/AuthController.ts b/src/auth/AuthController.ts index f1e2734..5d09617 100644 --- a/src/auth/AuthController.ts +++ b/src/auth/AuthController.ts @@ -26,7 +26,7 @@ export default abstract class AuthController extends Controller { protected abstract async getCheckAuth(req: Request, res: Response, next: NextFunction): Promise; protected async postLogout(req: Request, res: Response, next: NextFunction): Promise { - const proof = await req.authGuard.getProofForSession(req.session!); + const proof = await req.authGuard.getProof(req); await proof?.revoke(); req.flash('success', 'Successfully logged out.'); res.redirect(req.query.redirect_uri?.toString() || '/'); diff --git a/src/auth/AuthGuard.ts b/src/auth/AuthGuard.ts index 46cf1e6..5a0d380 100644 --- a/src/auth/AuthGuard.ts +++ b/src/auth/AuthGuard.ts @@ -7,15 +7,47 @@ import {PENDING_ACCOUNT_REVIEW_MAIL_TEMPLATE} from "../Mails"; import Mail from "../Mail"; import Controller from "../Controller"; import config from "config"; -import ModelFactory from "../db/ModelFactory"; export default abstract class AuthGuard

> { - public abstract async getProofForSession(session: Express.Session): Promise

; + protected abstract async getProofForSession(session: Express.Session): Promise

; - public async getProofForRequest(req: Request): Promise

{ + protected async getProofForRequest(req: Request): Promise

{ return null; } + public async getProof(req: Request): Promise

{ + let proof = await this.isAuthenticatedViaRequest(req); + if (!proof && req.session) { + proof = await this.isAuthenticated(req.session); + } + return proof; + } + + public async isAuthenticated(session: Express.Session): Promise

{ + if (!session.is_authenticated) return null; + + const proof = await this.getProofForSession(session); + + if (!proof || !await proof.isValid() || !await proof.isAuthorized()) { + await proof?.revoke(); + session.is_authenticated = false; + return null; + } + + return proof; + } + + public async isAuthenticatedViaRequest(req: Request): Promise

{ + const proof = await this.getProofForRequest(req); + + if (!proof || !await proof.isValid() || !await proof.isAuthorized()) { + await proof?.revoke(); + return null; + } + + return proof; + } + public async authenticateOrRegister( session: Express.Session, proof: P, @@ -61,28 +93,10 @@ export default abstract class AuthGuard

> { } // Login - session.auth_id = user.id; + session.is_authenticated = true; if (onLogin) await onLogin(user); } - public async isAuthenticated(session: Express.Session): Promise { - if (typeof session.auth_id !== 'number') return false; - - const proof = await this.getProofForSession(session); - - if (!proof || !await proof.isValid() || !await proof.isAuthorized()) { - await proof?.revoke(); - return false; - } - - return true; - } - - public async isAuthenticatedViaRequest(req: Request): Promise { - const proof = await this.getProofForRequest(req); - return Boolean(proof && await proof.isValid() && await proof.isAuthorized()); - } - } export class AuthError extends Error {