Files
WanJieDaoyou/apps/api/src/auth/access.guard.ts
T
2026-10-04 00:00:45 +08:00

73 lines
2.4 KiB
TypeScript

import {
HttpException,
Inject,
Injectable,
type CanActivate,
type ExecutionContext,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { isAdminIdentity, isAdminUserId } from '@server/lib/auth/adminAccess.js';
import { fromNodeHeaders } from 'better-auth/node';
import type { Response } from 'express';
import type { GameRequest } from '../http/request.js';
import { ACCESS_POLICY, type AccessPolicy } from './access.js';
import { SessionService } from './session.service.js';
@Injectable()
export class AccessGuard implements CanActivate {
constructor(
@Inject(Reflector) private readonly reflector: Reflector,
@Inject(SessionService) private readonly sessions: SessionService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const policy =
this.reflector.getAllAndOverride<AccessPolicy>(ACCESS_POLICY, [
context.getHandler(),
context.getClass(),
]) ?? 'user';
if (policy === 'public') return true;
const request = context.switchToHttp().getRequest<GameRequest>();
const response = context.switchToHttp().getResponse<Response>();
const session = await this.sessions.getSession(
fromNodeHeaders(request.headers),
);
session.headers?.forEach((value, key) => {
if (key.toLowerCase() !== 'set-cookie') response.setHeader(key, value);
});
for (const cookie of session.headers?.getSetCookie() ?? []) {
response.append('Set-Cookie', cookie);
}
const user = session.response?.user;
if (!user)
throw new HttpException({ success: false, error: '未授权访问' }, 401);
request.gameContext.user = {
id: user.id,
email: user.email,
name: user.name,
};
if (policy === 'admin' && !isAdminIdentity(user)) {
throw new HttpException({ success: false, error: '无管理员权限' }, 403);
}
if (policy === 'account-admin' && !isAdminUserId(user.id)) {
throw new HttpException(
{
success: false,
error: '账号管理需要在 ADMIN_USER_IDS 中配置当前管理员用户 ID',
},
403,
);
}
if (policy === 'active') {
const ref = await this.sessions.getActiveCultivator(user);
if (!ref)
throw new HttpException(
{ success: false, error: '当前没有活跃角色' },
404,
);
request.gameContext.activeCultivatorRef = ref;
}
return true;
}
}