NestJS 中基于角色的访问控制

NestJS 中基于角色的授权

授权是应用程序安全性的一个关键方面。它确保用户只能访问他们被允许访问的资源。在 NestJS(一种渐进式 Node.js 框架)中,由于其模块化设计和对装饰器的支持,实现基于角色的授权非常简单。

什么是基于角色的授权?

基于角色的授权根据用户的角色为其分配权限。常见角色包括“管理员”、“用户”和“访客”。每个角色都有一组可执行的预定义操作。例如:

  • 管理员:可以管理所有资源。
  • 用户:可以读取和更新自己的数据。
  • 访客:只能查看公开资源。
  • 通过实施基于角色的授权,您可以轻松控制应用程序内的访问。

    在 NestJS 中设置基于角色的授权

    以下是如何在 NestJS 中实现基于角色的授权:

    1.安装依赖项

    首先,确保您已设置 NestJS 项目。如果没有,您可以使用 CLI 创建一个:

    npm i -g @nestjs/cli
    nest new my-app

    接下来,安装 `@nestjs/passport` 和 `passport` 以支持身份验证:

    npm install @nestjs/passport passport passport-jwt
    npm install --save-dev @types/passport-jwt

    2. 定义角色

    创建一个“roles.enum.ts”文件来将角色定义为枚举:

    export enum Role {
      Admin = 'admin',
      User = 'user',
      Guest = 'guest',
    }

    3. 创建角色守卫

    NestJS 中的防护装置会在请求到达路由处理程序之前对其进行拦截。创建自定义防护装置以实施基于角色的访问控制。

    import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
    import { Reflector } from '@nestjs/core';
    import { Role } from './roles.enum';
    
    @Injectable()
    export class RolesGuard implements CanActivate {
      constructor(private reflector: Reflector) {}
    
      canActivate(context: ExecutionContext): boolean {
        const roles = this.reflector.get('roles', context.getHandler());
        if (!roles) {
          return true;
        }
        const request = context.switchToHttp().getRequest();
        const user = request.user;
        return roles.some((role) => user?.roles?.includes(role));
      }
    }

    4. 创建角色装饰器

    为了简化向路由处理程序添加角色的过程,请创建自定义装饰器:

    import { SetMetadata } from '@nestjs/common';
    import { Role } from './roles.enum';
    
    export const Roles = (...roles: Role[]) => SetMetadata('roles', roles);

    5. 全局或本地应用角色保护

    要使“RolesGuard”处于活动状态,您可以全局或本地应用它。对于全局应用,请将其添加到您的“AppModule”中:

    import { Module } from '@nestjs/common';
    import { APP_GUARD } from '@nestjs/core';
    import { RolesGuard } from './roles.guard';
    
    @Module({
      providers: [
        {
          provide: APP_GUARD,
          useClass: RolesGuard,
        },
      ],
    })
    export class AppModule {}

    对于本地应用,在特定的控制器或方法中使用它:

    import { Controller, Get, UseGuards } from '@nestjs/common';
    import { Roles } from './roles.decorator';
    import { RolesGuard } from './roles.guard';
    import { Role } from './roles.enum';
    
    @Controller('resources')
    @UseGuards(RolesGuard)
    export class ResourcesController {
      @Get()
      @Roles(Role.Admin, Role.User)
      findAll() {
        return 'This endpoint is accessible to Admins and Users.';
      }
    }

    6. 验证用户身份

    要识别用户的角色,请确保您的身份验证过程将角色添加到请求中的“用户”对象。这通常涉及解码 JWT 或使用会话存储。

    身份验证中间件示例

    import { Injectable, NestMiddleware } from '@nestjs/common';
    import { Request, Response, NextFunction } from 'express';
    
    @Injectable()
    export class AuthMiddleware implements NestMiddleware {
      use(req: Request, res: Response, next: NextFunction) {
        const token = req.headers['authorization'];
        if (token) {
          const decoded = this.decodeToken(token); // Implement JWT decoding
          req.user = decoded;
        }
        next();
      }
    
      private decodeToken(token: string): any {
        // Logic to decode JWT and retrieve user data
        return { roles: ['user'] }; // Example decoded payload
      }
    }

    测试实施

    启动您的应用程序并使用不同角色的用户测试端点。确保每个用户只能访问其角色允许的内容。

    示例请求

  • 管理员用户:应该访问所有路线。
  • 普通用户:应该访问特定于用户的路线。
  • 嘉宾:应该限制在公共路线。
  • 结论

    NestJS 中基于角色的授权简洁高效,这得益于装饰器、保护器和框架的模块化。通过遵循上述步骤,您可以保护应用程序的安全,同时保持灵活性和可扩展性。

    对于更复杂的场景,请考虑与**Casl**等外部库集成或实现基于属性的访问控制(ABAC)。