Javascript 有效JWT对于nestJS guard无效
我正在通过凭证头将JWT从我的客户端应用程序(nextJS with)传递到我的后端nestJS应用程序(使用graphQL)。在我的nestJS后端应用程序中,我试图实现一个auth guard,因此我在JWT.strategy.ts中使用一个自定义函数提取JWT 但是JwtStrategy不接受我的有效签名令牌。为了证明JWT是有效的,我为令牌添加了一些控制台输出。但是从未调用Javascript 有效JWT对于nestJS guard无效,javascript,jwt,passport.js,next.js,nestjs,Javascript,Jwt,Passport.js,Next.js,Nestjs,我正在通过凭证头将JWT从我的客户端应用程序(nextJS with)传递到我的后端nestJS应用程序(使用graphQL)。在我的nestJS后端应用程序中,我试图实现一个auth guard,因此我在JWT.strategy.ts中使用一个自定义函数提取JWT 但是JwtStrategy不接受我的有效签名令牌。为了证明JWT是有效的,我为令牌添加了一些控制台输出。但是从未调用validate()函数。我不明白为什么,因为令牌可以通过jwt验证。验证: JWT: eyJhbGciOiJIUz
validate()
函数。我不明白为什么,因为令牌可以通过jwt验证。验证:
JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7InVzZXJJZCI6MTIzLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaXNBZG1pbiI6dHJ1ZX0sImlhdCI6MTYwOTY3NTc4Nn0.LQy4QSesxJR91PyGGb_0mGZjpw9hlC4q7elIDs2CkLo
Secret: uGEFpuMDDdDQA3vCtZXPKgBYAriWWGrk
Decoded: {
user: { userId: 123, username: 'username', isAdmin: true },
iat: 1609675786
}
这是我的输出-它由jwt.verify()
解码:
我不知道我遗漏了什么,甚至不知道如何调试它,因为我的jwt.strategy.ts中没有输出,并且根本没有调用validate函数
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 }
}
}
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
}
}
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()
}
}
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 {}
jwt auth.guard.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 }
}
}
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
}
}
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()
}
}
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 {}
此分解器中使用了防护装置:
editor.resolver.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 }
}
}
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
}
}
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()
}
}
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 {}
验证模块.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 }
}
}
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
}
}
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()
}
}
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页面)创建的,具有:
我从您的jwt.strategy.ts文件中的nestJS文档示例中看到了两个不同之处,您可以更改并尝试一下
同步提取器和非异步提取器
默认情况下,passport jwt提取器是一个同步而非异步的提取器,因此您可以尝试更改提取器并删除异步,或者在调用它时添加wait
,,
从authHeaderAbarerToken函数中查找
所以还是改变你的想法
const cookieExtractor = async (req) => {
到
或者-在调用时添加wait
jwtFromRequest: await cookieExtractor(),
打电话给提取器,而不仅仅是传递它
根据JwtStrategy构造函数中的docs示例,他们调用提取器,而不像您那样传递它
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
因此,尝试在您的JwtStrategy构造函数中调用它
jwtFromRequest: cookieExtractor(), // (again - take care of sync / async)
哇,谢谢。过去几天我都没看到。谢谢你的好球。就在第一点做到了。传递函数是可以的,您不必调用它。我只需要删除async