PassportJS、NestJS:AuthGuard('jwt') 的 canActivate 方法

Posted

技术标签:

【中文标题】PassportJS、NestJS:AuthGuard(\'jwt\') 的 canActivate 方法【英文标题】:PassportJS, NestJS: canActivate method of AuthGuard('jwt')PassportJS、NestJS:AuthGuard('jwt') 的 canActivate 方法 【发布时间】:2021-04-09 21:58:21 【问题描述】:

有人知道我在哪里可以看到 AuthGuard('jwt') 中 canActivate 方法的完整代码吗?我意识到 canActivate 方法通过使用 console.log() 调用 JwtStrategy validate 方法,如下所示:

// jwt.strategy.ts

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) 
  constructor(
    private readonly configService: ConfigService,
    private readonly usersService: UsersService,
  ) 
    super(
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: true,
      secretOrKey: configService.get<string>('JWT_SECRET'),
    );
  

  async validate(payload: any) 
    try 
      const user = await this.usersService.getUserById(payload.id);
      // console.log is here
      console.log(user);
      return user;
     catch (e) 
      console.log(e);
      return null;
    
  

如果我使用原始的 canActivate 方法,则会调用 console.log。我认为 JwtStrategy 是一个中间件,所以只要有请求就会调用 validate 方法。但是,当我尝试覆盖 canActivate 方法来添加授权时,JwtStrategy validate 方法中的 console.log 没有被调用:

// jwt-auth.guard.ts

import  ExecutionContext, Injectable  from '@nestjs/common';
import  GqlExecutionContext  from '@nestjs/graphql';
import  AuthGuard  from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') 
  getRequest(context: ExecutionContext) 
    const ctx = GqlExecutionContext.create(context);
    return ctx.getContext().req;
  

  canActivate(context: ExecutionContext): boolean 
    try 
      // Override: handle authorization
      // return true or false
      // Should JwtStrategy.validate(something) be called here?
     catch (e) 
      console.log(e);
      return false;
    
  

然后我试图找到AuthGuard('jwt')的原始代码以了解其逻辑,但我无法做到。任何帮助将不胜感激,谢谢!

【问题讨论】:

【参考方案1】:

好的,所以这将是一个非常有趣的深入探讨。系好安全带。

Middleware 作为 express 方法在 NestJS 中仍然存在;也就是说,这不是 Express 中间件意义上的普通中间件。正如您提到的AuthGuard()#canActivate() 最终会调用适当的PassportStrategy。这些策略得到registered here,特别是在调用passport.use() 的第40-41 行。这将注册护照策略类的validate 方法以用于passport.verify()。大多数底层逻辑都非常抽象,阅读时可能会丢失上下文,因此请花点时间了解类、mixin(返回类的函数)和继承的概念。

Line 51 of AuthGuard 是最初创建 passportFn 的地方,在这个 passportFn 中,passport.authenticate 被调用(在其内部调用 passport.verify)(阅读 Passport 的代码更加令人困惑,所以我让您在需要时运行它)。

如果你想为你的canActivate() 方法添加一些额外的逻辑,你可以最终调用super.canActivate(context) 来调用最终调用passport.authenticate() 的原始canActivate() 方法,从而调用&lt;Strategy&gt;#validate。这可能看起来像

@Injectable()
export class CustomAuthGuard extends AuthGuard('jwt') 

  async canActivate(context: ExecutionContext): Promise<boolean> 
    // custom logic can go here
    const parentCanActivate = (await super.canActivate(context)) as boolean; // this is necessary due to possibly returning `boolean | Promise<boolean> | Observable<boolean>
    // custom logic goes here too
    return parentCanActivate && customCondition;
  

【讨论】:

非常感谢!那么,有没有什么办法可以在super.canActivate(context)之外访问&lt;Strategy&gt;#validate的返回值呢?例如,策略验证令牌,validate 返回包含 userId 的有效负载。我想在数据库中找到具有 userId 的用户,并使用保存在数据库中的用户的“角色”来处理授权。或者,由于我的自定义策略已经返回了完整的用户实体,所以我认为能够获得 validate 的返回值就足够了。 在后台,passport 将获取validate 返回的任何内容并将req.user 设置为它,因此如果您需要&lt;Strategy#&lt;validate&gt; 的返回值,您可以从@ 获取它987654348@ 哦,太好了!总而言之,super.canActivate(context) 返回一个布尔值是否为有效用户颁发了有效令牌,并且在调用它之后设置了req.user,因此我可以使用req.user 处理进一步的逻辑。感谢您的帮助!

以上是关于PassportJS、NestJS:AuthGuard('jwt') 的 canActivate 方法的主要内容,如果未能解决你的问题,请参考以下文章

NestJS & Passport:更改用户密码时更改 JWT 令牌?

javascript PassportJS身份验证设置#passportjs #cookiesession #nodejs

SANE 堆栈和 Passportjs

PassportJS - FacebookTokenStrategy 返回 404

同时使用 JWT 和 Passportjs

PassportJs 身份验证无限循环和执行(默认)查询