import type { IdentityUser } from "@/modules/identity/contracts"; import { IdentityAuthorizationError, type IdentityServerSession, } from "@/modules/identity/session"; import { authorizeAdminAccess, type AdminPermission, type AdminRole, } from "./auth-policy"; export type AdminSession = { user: IdentityUser; roles: AdminRole[]; permissions: AdminPermission[]; requiresMfa: boolean; identitySession: { id: string; token: string; expiresAt: Date; }; }; export class AdminAuthorizationError extends Error { constructor( message: string, readonly status: 401 | 403 | 503, ) { super(message); this.name = "AdminAuthorizationError"; } } export type AdminAuthorizationDependencies = { readAuthProvider: () => string | undefined; readRequestHeaders: () => Headers | Promise; readIdentityConfig: () => IdentityConfig; resolveIdentitySurface: ( host: string | null, config: IdentityConfig, ) => "user" | "admin" | null; requireIdentitySession: ( requestHeaders: Headers, ) => Promise; loadAdminSession: ( user: IdentityUser, identitySession: AdminSession["identitySession"], ) => Promise; }; export async function authorizeAdminRequest( permission: AdminPermission, requestHeaders: Headers | undefined, dependencies: AdminAuthorizationDependencies, ): Promise { try { if (dependencies.readAuthProvider()?.trim() !== "self-hosted") { throw new AdminAuthorizationError("后台身份服务未启用", 403); } const adminHeaders = requestHeaders ?? new Headers(await dependencies.readRequestHeaders()); const identityConfig = dependencies.readIdentityConfig(); if ( dependencies.resolveIdentitySurface( adminHeaders.get("host"), identityConfig, ) !== "admin" ) { throw new AdminAuthorizationError("无权访问后台", 403); } const identitySession = await dependencies.requireIdentitySession(adminHeaders); const session = await dependencies.loadAdminSession(identitySession.user, { id: identitySession.sessionId, token: identitySession.sessionToken, expiresAt: identitySession.expiresAt, }); const authorization = authorizeAdminAccess( identitySession.user, session.permissions, permission, ); if (!authorization.allowed) { throw new AdminAuthorizationError("无权执行此操作", authorization.status); } return session; } catch (error) { if (error instanceof AdminAuthorizationError) throw error; if (error instanceof IdentityAuthorizationError) { throw new AdminAuthorizationError( error.status === 401 ? "请先登录" : "无权访问后台", error.status, ); } throw new AdminAuthorizationError("后台服务暂时不可用", 503); } }