NestJs - 无法在 RolesGuard 中获取用户上下文
Posted
技术标签:
【中文标题】NestJs - 无法在 RolesGuard 中获取用户上下文【英文标题】:NestJs - Unable to get user context in RolesGuard 【发布时间】:2018-11-20 22:17:06 【问题描述】:我使用 NestJS 作为客户端 API 的框架。在框架内,我们使用了一个运行良好的非常标准的 Passport/JWT 身份验证基础设施。当找到承载令牌时,我们的 AuthGuard 正在触发,并且在安全的 API 端点中,我可以通过“@Res() 请求”注入 HTTP 上下文并访问包含我的 Jwt 令牌有效负载的“request.user”属性.
除此之外,我们正在尝试以与文档中提供的示例代码和 GitHub 上的一些示例项目非常相似的方式实现“RolesGuard”(其中没有一个实际使用此防护,但它们将其包含为一个样本守卫)。
我们的问题是我们的 AuthGuard 触发并验证 Jwt 令牌,然后我们的 RolesGuard 触发但它传递的请求对象没有附加到请求的用户元数据。
我们 RolesGuard 中的关键代码是:
const request = context.switchToHttp().getRequest();
const user = request.user;
if (!user)
return false;
在上面的截图中,用户总是假的。有没有人在 Nest 中编写了一个基于角色/权限的守卫,成功地访问了当前用户的范围?所有代码都在触发,并且所有内容都已正确注册。
-凯文
【问题讨论】:
【参考方案1】:最终这似乎是守卫的排序问题,并且看起来不容易解决(没有框架允许对排序进行一些控制)。
我希望在全局范围内注册 RolesGuard,但这会导致它首先注册并首先触发。
@UseGuards(AuthGuard('jwt'), RolesGuard)
@Roles('admin')
如果我在端点级别注册它并将其放在 AuthGuard 之后,那么它会第二次触发,我会在防护本身中获得我期望的用户上下文。它并不完美,但它有效。
-凯文
【讨论】:
这应该被标记为答案。它工作得很好,可以明确地命令守卫。 它可以通过中间件解决并通过元数据查找方法,但我不会打扰...... 这可以使用快速会话解决吗?或者这不是一个好方法? 我发现这个答案完全可以接受,应该可以解决 99% 的用例。我假设您正在尝试将此逻辑实现为 global 防护,它将在您的 JWT 身份验证防护之前执行(假设它已在控制器或路由级别注册)。查看请求生命周期here。顺序:全局守卫 -> 控制器守卫 -> 路由守卫【参考方案2】:在端点级别注册 RoleGuard 并将其放在 AuthGuard 之后,然后它会第二次触发,我在防护本身中获得了我期望的用户上下文。 不要在模块中注册 RoleGuard,因为它会先注册并先触发。
*.module.ts
imports: [],
providers: [provide: APP_GUARD, useClass: RolesGuard ,], // remove guard
controllers: [],
exports: [],
【讨论】:
【参考方案3】:如果其他人偶然发现了这个问题:将多个守卫放入一个 @UseGuards
装饰器是可行的,但如果你想让它们分开(例如,如果你使用自定义装饰器),你可以让第二个守卫访问 @ 987654323@ 将其放置在 将用户置于请求对象上的 @UseGuards
调用之前,如下例所示:
@RestrictTo(UserAuthorities.admin)
@UseGuards(JwtAuthGuard)
@Get("/your-route")
看来这是how decorators work in TypeScript的结果。
【讨论】:
【参考方案4】:让你的 RolesGuard 扩展 AuthGuard('StrategyName') 然后调用 super.canActivate 例如:
@Injectable()
export class RolesGuard extends AuthGuard('jwt')
async canActivate(context: ExecutionContext): Promise<boolean>
// call AuthGuard in order to ensure user is injected in request
const baseGuardResult = await super.canActivate(context);
if(!baseGuardResult)
// unsuccessful authentication return false
return false;
// successfull authentication, user is injected
const user = context.switchToHttp().getRequest();
换句话说,您必须先进行身份验证,然后再进行授权
【讨论】:
以上是关于NestJs - 无法在 RolesGuard 中获取用户上下文的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 typeorm (NestJS) 在 SQL Server 中插入 bigint
无法在所有客户端 angular/nestjs 套接字 io 中接收数据