繁体   English   中英

有效的 JWT 对 nestJS 防护无效

[英]Valid JWT is invalid for nestJS guard

我通过凭据 header 从我的客户端应用程序(带有 nextAuth 的nextJS )将 JWT 传递给我的后端nestJS 应用程序(使用graphQL)。 在我的nestJS后端应用程序中,我试图实现一个身份验证保护,所以我在我的jwt.strategy.ts中使用自定义function提取JWT

但是 JwtStrategy 不接受我的有效签名令牌。 为了证明 JWT 是有效的,我放了一些控制台 output 作为令牌。 但是validate() function 永远不会被调用。 我不明白为什么,因为可以使用jwt.verify验证令牌:

这是我的 output - 它由jwt.verify()解码:

JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7InVzZXJJZCI6MTIzLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaXNBZG1pbiI6dHJ1ZX0sImlhdCI6MTYwOTY3NTc4Nn0.LQy4QSesxJR91PyGGb_0mGZjpw9hlC4q7elIDs2CkLo
Secret: uGEFpuMDDdDQA3vCtZXPKgBYAriWWGrk
Decoded: {
  user: { userId: 123, username: 'username', isAdmin: true },
  iat: 1609675786
}

我没有看到,我缺少什么,我什至看不到如何调试它,因为我的 jwt.strategy.ts 中没有 output 并且根本没有调用验证函数。

jwt.strategy.ts

import jwt from 'jsonwebtoken'
// import { JwtService } from '@nestjs/jwt'
import { Strategy } from 'passport-jwt'
import { PassportStrategy } from '@nestjs/passport'
import { Injectable } from '@nestjs/common'
import cookie from 'cookie'

import { getConfig } from '@myapp/config'
const { secret } = getConfig()

const parseCookie = (cookies) => cookie.parse(cookies || '')

const cookieExtractor = async (req) => {
  let token = null
  if (req?.headers?.cookie) {
    token = parseCookie(req.headers.cookie)['next-auth.session-token']
  }

  // output as shown above
  console.log('JWT:', token)
  console.log('Secret:', secret)
  const decoded = await jwt.verify(token, secret, { algorithms: ['HS256'] })
  console.log('Decoded: ', decoded)

  return token
}

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: cookieExtractor,
      ignoreExpiration: true,
      secretOrKey: secret
    })
  }

  async validate(payload: any) {
    console.log('payload:', payload) // is never called

    return { userId: payload.sub, username: payload.username }
  }
}

jwt-auth.guard.ts

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

@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
  getRequest(context: GqlExecutionContext) {
    const ctx = GqlExecutionContext.create(context)
    return ctx.getContext().req
  }
}

此解析器中使用了防护:

editor.resolver.ts

import { Query, Resolver } from '@nestjs/graphql'
import { UseGuards } from '@nestjs/common'
import { GqlAuthGuard } from '../auth/jwt-auth.guard'

@Resolver('Editor')
export class EditorResolvers {
  constructor(private readonly editorService: EditorService) {}

  @UseGuards(GqlAuthGuard)
  @Query(() => [File])
  async getFiles() {
    return this.editorService.getFiles()
  }
}

auth.module.ts

import { Module } from '@nestjs/common'
import { AuthController } from './auth.controller'
import { AuthService } from './auth.service'
import { PassportModule } from '@nestjs/passport'
import { LocalStrategy } from './local.strategy'
import { JwtStrategy } from './jwt.strategy'
import { UsersModule } from '../users/users.module'
import { JwtModule } from '@nestjs/jwt'

import { getConfig } from '@myApp/config'
const { secret } = getConfig()

@Module({
  imports: [
    UsersModule,
    PassportModule.register({ defaultStrategy: 'jwt' }),
    JwtModule.register({
      secret,
      verifyOptions: { algorithms: ['HS256'] },
      signOptions: { expiresIn: '1d' }
    })
  ],
  controllers: [AuthController],
  providers: [AuthService, JwtStrategy, LocalStrategy],
  exports: [AuthService]
})
export class AuthModule {}

令牌是在服务器端(nextJS api 页面)创建的:

const encode = async ({ secret, token }) => jwt.sign(token, secret, { algorithm: 'HS256' })

我从您的jwt.strategy.ts文件中看到了与 nestJS 文档示例的 2 个差异,您可以更改并试一试。

https://docs.nestjs.com/security/authentication#implementing-passport-jwt

  1. 同步提取器而不是异步

默认情况下,passport-jwt 提取器我们可以看到这是一个同步而不是异步,因此您可以尝试更改您的提取器并删除异步,或者在调用它时添加等待。

https://github.com/mikenicholson/passport-jwt/blob/master/lib/extract_jwt.js ,查找fromAuthHeaderAsBearerToken function。

所以或者改变你的

const cookieExtractor = async (req) => {

const cookieExtractor = (req) => {

或 - 在您调用它时添加等待

jwtFromRequest: await cookieExtractor(),
  1. 调用提取器,而不仅仅是通过它

通过JwtStrategy 构造函数中的文档示例,他们调用提取器而不是像你一样传递它

jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),

所以尝试在你的JwtStrategy 构造函数中调用它

jwtFromRequest: cookieExtractor(),    // (again - take care of sync / async)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM