重构 API 为 8 领域 + 应用层架构
将后端模块拆分为 domains、applications、shared 三层,结算计算器移入 domain 纯函数目录,API 路径与测试保持不变。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
87
apps/api/src/domains/identity/guards.ts
Normal file
87
apps/api/src/domains/identity/guards.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { IS_PUBLIC_KEY, PERMISSIONS_KEY } from '../../shared/common/decorators';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard extends AuthGuard('jwt') {
|
||||
constructor(private reflector: Reflector) {
|
||||
super();
|
||||
}
|
||||
|
||||
canActivate(context: ExecutionContext) {
|
||||
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
if (isPublic) return true;
|
||||
return super.canActivate(context);
|
||||
}
|
||||
|
||||
handleRequest<TUser = unknown>(err: Error | null, user: TUser): TUser {
|
||||
if (err || !user) throw err || new UnauthorizedException();
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class PermissionsGuard implements CanActivate {
|
||||
constructor(private reflector: Reflector) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const required = this.reflector.getAllAndOverride<string[]>(PERMISSIONS_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
if (!required?.length) return true;
|
||||
|
||||
const { user } = context.switchToHttp().getRequest();
|
||||
const userPerms: string[] = user?.permissions ?? [];
|
||||
if (user?.role === 'SUPER_ADMIN') return true;
|
||||
|
||||
const hasAll = required.every((p) => userPerms.includes(p));
|
||||
if (!hasAll) throw new ForbiddenException('Insufficient permissions');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function UserTypeGuard(...types: string[]) {
|
||||
@Injectable()
|
||||
class MixedUserTypeGuard implements CanActivate {
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const { user } = context.switchToHttp().getRequest();
|
||||
if (!types.includes(user?.userType)) {
|
||||
throw new ForbiddenException('Access denied for this portal');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return MixedUserTypeGuard;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class PlayerGuard implements CanActivate {
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const { user } = context.switchToHttp().getRequest();
|
||||
if (user?.userType !== 'PLAYER') throw new ForbiddenException('Player access only');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class AdminGuard implements CanActivate {
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const { user } = context.switchToHttp().getRequest();
|
||||
if (user?.userType !== 'ADMIN') throw new ForbiddenException('Admin access only');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class AgentGuard implements CanActivate {
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const { user } = context.switchToHttp().getRequest();
|
||||
if (user?.userType !== 'AGENT') throw new ForbiddenException('Agent access only');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user