add cache to auth

This commit is contained in:
2025-01-24 19:24:27 +05:30
parent 59ce61d3a6
commit 405338c314
8 changed files with 125 additions and 67 deletions

View File

@@ -3,8 +3,13 @@ import { FastifyReply, FastifyRequest } from "fastify";
import { getToken } from "./tokens/token.service";
import { Claim } from "./utils/claims";
import { OAuth2Namespace } from "@fastify/oauth2";
import { getSession } from "./auth/auth.service";
import { roles, rules } from "./utils/roles";
import { deleteSession, getSession } from "./auth/auth.service";
import { rules } from "./utils/roles";
import {
cacheSession,
getCachedSession,
removeCachedSession,
} from "./utils/cache";
export type AuthenticatedUser = {
sid?: string;
@@ -14,6 +19,7 @@ export type AuthenticatedUser = {
role?: string;
tenantId: string;
claims: Array<Claim>;
expiry?: string;
};
declare module "fastify" {
@@ -56,35 +62,21 @@ export async function authHandler(req: FastifyRequest, res: FastifyReply) {
claims: tokenInDb.claims as Array<Claim>,
};
} else {
const sessionInDb = await getSession(authHeader);
if (sessionInDb === null)
let session = getCachedSession(authHeader);
if (!session) {
session = await getSession(authHeader);
cacheSession(authHeader, session);
}
if (!session) return res.code(401).send({ error: "invalid_token" });
if (new Date() > new Date(session.expiry)) {
removeCachedSession(authHeader);
await deleteSession(authHeader);
return res.code(401).send({ error: "invalid_token" });
if (new Date() > new Date(sessionInDb.expiresAt)) {
await sessionInDb.deleteOne();
return res.code(401).send({ error: "session_expired" });
}
//@ts-ignore
if (!rules[sessionInDb.user.role]) {
return res.code(401).send({ error: "no role" });
}
req.user = {
sid: authHeader,
//@ts-ignore
type: sessionInDb.user.type,
//@ts-ignore
userId: sessionInDb.user.id,
//@ts-ignore
tenantId: sessionInDb.user.tenantId,
//@ts-ignore
orgId: sessionInDb.user.orgId,
//@ts-ignore
role: sessionInDb.user.role,
//@ts-ignore
claims: rules[sessionInDb.user.role].claims,
};
req.user = session;
}
}

View File

@@ -1,6 +1,6 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { getUserByEmail, updateUser } from "../user/user.service";
import { createSession, getSession } from "./auth.service";
import { createSession, deleteSession, getSession } from "./auth.service";
export async function authRoutes(fastify: FastifyInstance) {
fastify.get(
@@ -55,10 +55,7 @@ export async function authRoutes(fastify: FastifyInstance) {
if (!req.headers.authorization) return res.code(200).send();
const auth = req.headers.authorization.split(" ")[1];
const sessionInDb = await getSession(auth);
if (sessionInDb === null) return res.code(200).send();
await sessionInDb.deleteOne();
await deleteSession(auth);
return res.code(200).send();
});
}

View File

@@ -1,4 +1,7 @@
import { AuthenticatedUser } from "../auth";
import { userModel } from "../user/user.schema";
import { generateToken } from "../utils/id";
import { rules } from "../utils/roles";
import { sessionModel } from "./auth.schema";
export async function createSession(userId: string, ip?: string, ua?: string) {
@@ -19,6 +22,28 @@ export async function createSession(userId: string, ip?: string, ua?: string) {
return newSession;
}
export async function getSession(sessionId: string) {
return await sessionModel.findOne({ sid: sessionId }).populate("user");
export async function getSession(
sessionId: string
): Promise<AuthenticatedUser | null> {
console.log("DB HIT");
const session = await sessionModel.findOne({ sid: sessionId });
if (session === null) return null;
const user = await userModel.findById(session.user);
if (user === null) return null;
return {
sid: session.id,
type: "user",
userId: user.id,
orgId: user.orgId ? user.orgId.toString() : null,
role: user.role,
tenantId: user.tenantId,
claims: rules[user.role].claims ?? [],
expiry: new Date(session.expiresAt).toISOString(),
};
}
export async function deleteSession(sessionId: string) {
return await sessionModel.deleteOne({ sid: sessionId });
}

View File

@@ -1,37 +1,41 @@
import { buildJsonSchemas } from "fastify-zod";
import mongoose from "mongoose";
import mongoose, { InferSchemaType } from "mongoose";
import { z } from "zod";
import { roles } from "../utils/roles";
export const userModel = mongoose.model(
"user",
new mongoose.Schema({
tenantId: {
type: String,
required: true,
},
pid: {
type: String,
unique: true,
required: true,
},
orgId: mongoose.Types.ObjectId,
firstName: String,
lastName: String,
name: String,
email: {
type: String,
unique: true,
required: true,
},
avatar: String,
status: String,
role: String,
createdAt: Date,
createdBy: mongoose.Types.ObjectId,
lastLogin: Date,
})
);
const userSchema = new mongoose.Schema({
tenantId: {
type: String,
required: true,
},
pid: {
type: String,
unique: true,
required: true,
},
orgId: mongoose.Types.ObjectId,
firstName: String,
lastName: String,
name: String,
email: {
type: String,
unique: true,
required: true,
},
avatar: String,
status: String,
role: {
type: String,
required: true,
},
createdAt: Date,
createdBy: mongoose.Types.ObjectId,
lastLogin: Date,
});
export const userModel = mongoose.model("user", userSchema);
export type User = InferSchemaType<typeof userSchema>;
const userCore = {
firstName: z.string().max(30),

19
src/utils/cache.ts Normal file
View File

@@ -0,0 +1,19 @@
import { LRUCache } from "lru-cache";
import { AuthenticatedUser } from "../auth";
const sessionCache = new LRUCache<string, AuthenticatedUser>({
max: 100,
ttl: 1000 * 60 * 60,
});
export function cacheSession(key: string, user: AuthenticatedUser) {
sessionCache.set(key, user);
}
export function getCachedSession(key: string) {
return sessionCache.get(key);
}
export function removeCachedSession(key: string) {
sessionCache.delete(key);
}