fix permissions and teacher attendance workflows
This commit is contained in:
@@ -2,18 +2,19 @@ import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { IS_PUBLIC_KEY } from '../decorators/public.decorator';
|
||||
import { PERMISSION_KEY } from '../decorators/permission.decorator';
|
||||
import { AUTHENTICATED_KEY } from '../decorators/authenticated.decorator';
|
||||
|
||||
/**
|
||||
* 权限守卫 — 默认放行策略(⚠️ 安全关键)
|
||||
* 权限守卫 — 默认拒绝策略(安全关键)
|
||||
*
|
||||
* 当 handler/controller 上不存在 @RequirePermission 时,守卫放行(仅需登录即可访问)。
|
||||
* 这是有意的设计选择:所有敏感路由必须显式标注 @RequirePermission。
|
||||
* 当 handler/controller 上不存在 @RequirePermission、@Authenticated 且未标记 @Public 时,守卫拒绝访问。
|
||||
* 所有路由必须显式声明公开、仅登录或所需权限。
|
||||
*
|
||||
* ⚠️ 新增路由时务必添加 @RequirePermission,否则该路由对所有已认证用户开放!
|
||||
* ⚠️ 新增路由时务必添加 @RequirePermission、@Authenticated 或 @Public。
|
||||
* 建议配合 lint 规则确保无遗漏。
|
||||
*/
|
||||
@Injectable()
|
||||
export class PermissionGuard implements CanActivate {
|
||||
@Injectable()
|
||||
export class PermissionGuard implements CanActivate {
|
||||
constructor(private reflector: Reflector) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
@@ -24,20 +25,28 @@ import { PERMISSION_KEY } from '../decorators/permission.decorator';
|
||||
]);
|
||||
if (isPublic) return true;
|
||||
|
||||
// 2. 获取所需权限(getAllAndMerge 合并 handler+class 层的所有 metadata)
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const user = request.user;
|
||||
|
||||
// 2. @Authenticated() 只要求已登录,具体 JWT 有效性由 JwtAuthGuard 负责。
|
||||
const authenticatedOnly = this.reflector.getAllAndOverride<boolean>(AUTHENTICATED_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
if (authenticatedOnly) return !!user;
|
||||
|
||||
// 3. 获取所需权限(getAllAndMerge 合并 handler+class 层的所有 metadata)
|
||||
const requiredPermissions = this.reflector.getAllAndMerge<string[]>(PERMISSION_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
// 无装饰器 = 仅需登录即可,放行
|
||||
if (!requiredPermissions || requiredPermissions.length === 0) return true;
|
||||
// 无权限声明且非 @Public/@Authenticated:默认拒绝,避免新增接口意外裸奔
|
||||
if (!requiredPermissions || requiredPermissions.length === 0) return false;
|
||||
|
||||
// 3. 从 JWT payload 获取用户权限
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const user = request.user;
|
||||
// 4. 从 JWT payload 获取用户权限
|
||||
if (!user || !user.permissions || !Array.isArray(user.permissions)) return false;
|
||||
|
||||
// 4. OR 匹配:用户拥有 requiredPermissions 中任一权限即可通过
|
||||
// 5. OR 匹配:用户拥有 requiredPermissions 中任一权限即可通过
|
||||
return requiredPermissions.some((p) => user.permissions.includes(p));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user