带有守卫/装饰器的身份验证和角色:如何传递用户对象?

sto*_*nie 2 nestjs

在 Guards/Decorators 的帮助下,我尝试首先检查 JWT,然后检查用户拥有的角色。

我已阅读有关身份验证、守卫和装饰器的文档并了解它们背​​后的原理。

但是,我无法做的是以某种方式使 JWT-Guard 中经过身份验证的用户可供 Roles-Guards 使用。

在我发现的每个例子中,正是我感兴趣的这部分被跳过/遗漏了......

感谢每一个提示!

这是我最近的尝试:

jwt.strategy.ts

import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { JwtPayload } from './jwt.model';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      passReqToCallback: true,
      ignoreExpiration: false,
      secretOrKey: '0000',
      expiresIn: '3 days'
    });
  }

  async validate(payload: JwtPayload) {
    return {
      id: payload.id,
      email: payload.email,
      username: payload.username
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

角色.guard.ts

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {
  }

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());

    if (!roles) {
      return false;
    }

    const request = context.switchToHttp().getRequest();
    const user = request.user ??? // THIS is what is missing

    return roles.some((role) => {
      return role === user.role;
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

角色装饰器.ts

import { SetMetadata } from '@nestjs/common';

export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
Run Code Online (Sandbox Code Playgroud)

用户.controller.ts

@UseGuards(AuthGuard('jwt'))
@Roles('admin', 'member')
@Get('/')
async doSomething(@Req() req): Promise<User> {
  return await this.usersService.doSomething(req.user.id);
}
Run Code Online (Sandbox Code Playgroud)

小智 6

您的装饰器和守卫看起来不错,但从文件片段来看,users.controller.ts尚不清楚角色守卫是否实际应用于该GET /路线。

不过,我确实有一个 NestJS 应用程序,它的设置非常相似,基于Guards 文档。以下代码users.controller.ts按预期工作:

@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get()
  @Roles(UserRole.ADMIN)
  public async index(): Promise<User[]> {
    return this.userService.findAll();
  }

  // ...
}
Run Code Online (Sandbox Code Playgroud)

请注意如何在同一范围内激活身份验证和角色防护,并且该范围JwtAuthGuard之前 RolesGuard添加的。如果我要更改守卫的顺序,那么将RolesGuard无法检索请求的用户。

另外,您可能想看看不久前的类似问题,其中包含有关不同范围内的守卫顺序的一些详细信息。