Redone
This commit is contained in:
@@ -1,103 +1,115 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import fp from "fastify-plugin";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { secrets } from "../utils/secrets";
|
||||
import { FastifyInstance } from "fastify"
|
||||
import fp from "fastify-plugin"
|
||||
import jwt from "jsonwebtoken"
|
||||
import { secrets } from "../utils/secrets"
|
||||
|
||||
import {
|
||||
authUserRoles,
|
||||
authRolePermissions,
|
||||
} from "../../db/schema"
|
||||
|
||||
import { eq, and } from "drizzle-orm"
|
||||
|
||||
export default fp(async (server: FastifyInstance) => {
|
||||
server.addHook("preHandler", async (req, reply) => {
|
||||
// 1️⃣ Token holen (Header oder Cookie)
|
||||
const cookieToken = req.cookies?.token;
|
||||
const authHeader = req.headers.authorization;
|
||||
const headerToken = authHeader?.startsWith("Bearer ")
|
||||
? authHeader.slice(7)
|
||||
: null;
|
||||
// 1️⃣ Token aus Header oder Cookie lesen
|
||||
const cookieToken = req.cookies?.token
|
||||
const authHeader = req.headers.authorization
|
||||
|
||||
const headerToken =
|
||||
authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null
|
||||
|
||||
const token =
|
||||
headerToken && headerToken.length > 10 ? headerToken : cookieToken || null;
|
||||
|
||||
|
||||
|
||||
/*let token = null
|
||||
|
||||
if(headerToken !== null && headerToken.length > 10){
|
||||
token = headerToken
|
||||
} else if(cookieToken ){
|
||||
token = cookieToken
|
||||
}*/
|
||||
headerToken && headerToken.length > 10
|
||||
? headerToken
|
||||
: cookieToken || null
|
||||
|
||||
if (!token) {
|
||||
return reply.code(401).send({ error: "Authentication required" });
|
||||
return reply.code(401).send({ error: "Authentication required" })
|
||||
}
|
||||
|
||||
try {
|
||||
// 2️⃣ JWT verifizieren
|
||||
const payload = jwt.verify(token, secrets.JWT_SECRET!) as {
|
||||
user_id: string;
|
||||
email: string;
|
||||
tenant_id: number;
|
||||
};
|
||||
user_id: string
|
||||
email: string
|
||||
tenant_id: number | null
|
||||
}
|
||||
|
||||
if (!payload?.user_id) {
|
||||
return reply.code(401).send({ error: "Invalid token" });
|
||||
return reply.code(401).send({ error: "Invalid token" })
|
||||
}
|
||||
|
||||
req.user = payload;
|
||||
// Payload an Request hängen
|
||||
req.user = payload
|
||||
|
||||
if(req.user.tenant_id) {
|
||||
// 3️⃣ Rolle des Nutzers im Tenant laden
|
||||
const { data: roleData, error: roleError } = await server.supabase
|
||||
.from("auth_user_roles")
|
||||
.select("role_id")
|
||||
.eq("user_id", payload.user_id)
|
||||
.eq("tenant_id", payload.tenant_id)
|
||||
.maybeSingle();
|
||||
|
||||
if (roleError) {
|
||||
console.log("Error fetching user role", roleError);
|
||||
return reply.code(500).send({ error: "Failed to load user role" });
|
||||
}
|
||||
|
||||
if (!roleData) {
|
||||
return reply.code(403).send({ error: "No role assigned for this tenant" });
|
||||
}
|
||||
|
||||
const roleId = roleData.role_id;
|
||||
|
||||
// 4️⃣ Berechtigungen der Rolle laden
|
||||
const { data: permissions, error: permsError } = await server.supabase
|
||||
.from("auth_role_permissions")
|
||||
.select("permission")
|
||||
.eq("role_id", roleId);
|
||||
|
||||
if (permsError) {
|
||||
console.log("Failed to load permissions", permsError);
|
||||
return reply.code(500).send({ error: "Permission lookup failed" });
|
||||
}
|
||||
|
||||
const perms = permissions?.map((p) => p.permission) ?? [];
|
||||
|
||||
// 5️⃣ An Request hängen
|
||||
req.role = roleId;
|
||||
req.permissions = perms;
|
||||
req.hasPermission = (perm: string) => perms.includes(perm);
|
||||
// Multi-Tenant Modus ohne ausgewählten Tenant → keine Rollenprüfung
|
||||
if (!req.user.tenant_id) {
|
||||
return
|
||||
}
|
||||
|
||||
const tenantId = req.user.tenant_id
|
||||
const userId = req.user.user_id
|
||||
|
||||
// --------------------------------------------------------
|
||||
// 3️⃣ Rolle des Nutzers im Tenant holen
|
||||
// --------------------------------------------------------
|
||||
const roleRows = await server.db
|
||||
.select()
|
||||
.from(authUserRoles)
|
||||
.where(
|
||||
and(
|
||||
eq(authUserRoles.user_id, userId),
|
||||
eq(authUserRoles.tenant_id, tenantId)
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
|
||||
if (roleRows.length === 0) {
|
||||
return reply
|
||||
.code(403)
|
||||
.send({ error: "No role assigned for this tenant" })
|
||||
}
|
||||
|
||||
const roleId = roleRows[0].role_id
|
||||
|
||||
// --------------------------------------------------------
|
||||
// 4️⃣ Berechtigungen der Rolle laden
|
||||
// --------------------------------------------------------
|
||||
const permissionRows = await server.db
|
||||
.select()
|
||||
.from(authRolePermissions)
|
||||
.where(eq(authRolePermissions.role_id, roleId))
|
||||
|
||||
const permissions = permissionRows.map((p) => p.permission)
|
||||
|
||||
// --------------------------------------------------------
|
||||
// 5️⃣ An Request hängen für spätere Nutzung
|
||||
// --------------------------------------------------------
|
||||
req.role = roleId
|
||||
req.permissions = permissions
|
||||
req.hasPermission = (perm: string) => permissions.includes(perm)
|
||||
|
||||
} catch (err) {
|
||||
return reply.code(401).send({ error: "Invalid or expired token" });
|
||||
console.error("JWT verification error:", err)
|
||||
return reply.code(401).send({ error: "Invalid or expired token" })
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Fastify TypeScript Erweiterungen
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// 🧩 Fastify Type Declarations
|
||||
declare module "fastify" {
|
||||
interface FastifyRequest {
|
||||
user: {
|
||||
user_id: string;
|
||||
email: string;
|
||||
tenant_id: number;
|
||||
};
|
||||
role: string;
|
||||
permissions: string[];
|
||||
hasPermission: (permission: string) => boolean;
|
||||
user_id: string
|
||||
email: string
|
||||
tenant_id: number | null
|
||||
}
|
||||
role: string
|
||||
permissions: string[]
|
||||
hasPermission: (permission: string) => boolean
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user