feat(p1): complete P1 foundation stage
- monorepo: pnpm workspace + go.work + pyproject.toml + commitlint/husky - infra: docker-compose (minimal + full profiles) + init-sql + prometheus - arch-scan: multi-language scanner skeleton (TS/Go/Python/Proto) - shared-proto: buf v2 + classes.proto (ClassService CRUD contract) - api-gateway: Go/Gin + JWT HS256 auth + reverse proxy + request ID - classes: NestJS golden template (error system + observability + middleware + CRUD + tests) - teacher-portal: Next.js + paper-feel UI design system - CI/CD: 4 workflows (go/ts/py/proto) - docs: migration guide + project_rules + coding-standards + git-workflow + ui-design-system + 004 + 9 module READMEs + known-issues + spec/plan migration + roadmap
This commit is contained in:
50
services/classes/src/middleware/permission.guard.ts
Normal file
50
services/classes/src/middleware/permission.guard.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||
import type { Reflector } from '@nestjs/core';
|
||||
import { PermissionDeniedError } from '../shared/errors/application-error.js';
|
||||
import type { AuthenticatedRequest } from './auth.middleware.js';
|
||||
|
||||
export type Permission =
|
||||
| 'CLASS_CREATE'
|
||||
| 'CLASS_READ'
|
||||
| 'CLASS_UPDATE'
|
||||
| 'CLASS_DELETE';
|
||||
|
||||
export const Permissions = {
|
||||
CLASS_CREATE: 'CLASS_CREATE' as const,
|
||||
CLASS_READ: 'CLASS_READ' as const,
|
||||
CLASS_UPDATE: 'CLASS_UPDATE' as const,
|
||||
CLASS_DELETE: 'CLASS_DELETE' as const,
|
||||
};
|
||||
|
||||
const ROLE_PERMISSIONS: Record<string, Permission[]> = {
|
||||
admin: [Permissions.CLASS_CREATE, Permissions.CLASS_READ, Permissions.CLASS_UPDATE, Permissions.CLASS_DELETE],
|
||||
teacher: [Permissions.CLASS_CREATE, Permissions.CLASS_READ, Permissions.CLASS_UPDATE],
|
||||
student: [Permissions.CLASS_READ],
|
||||
parent: [Permissions.CLASS_READ],
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class PermissionGuard implements CanActivate {
|
||||
constructor(private readonly requiredPermission: Permission) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const request = context.switchToHttp().getRequest<AuthenticatedRequest>();
|
||||
const roles = request.userRoles ?? [];
|
||||
|
||||
for (const role of roles) {
|
||||
const perms = ROLE_PERMISSIONS[role];
|
||||
if (perms && perms.includes(this.requiredPermission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
throw new PermissionDeniedError(this.requiredPermission);
|
||||
}
|
||||
}
|
||||
|
||||
// 工厂函数,用于装饰器(修复:import Reflector 已移至文件顶部)
|
||||
export function createPermissionGuardFactory(_reflector: Reflector) {
|
||||
return {
|
||||
create: (permission: Permission) => new PermissionGuard(permission),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user