nob*_*are 3 passport.js jwt-auth nestjs passport-jwt
使用 Postman 测试我的端点,我能够成功“登录”并接收 JWT 令牌。现在,我正在尝试访问一个据称具有 的端点,AuthGuard以确保现在我已登录,我现在可以访问它。
但是,401 Unauthorized即使在 Postman 中提供 JWT 令牌,它也会不断返回。
这是我的代码:
用户控制器.ts
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@UseGuards(AuthGuard())
@Get()
getUsers() {
return this.usersService.getUsersAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
jwt.strategy.ts
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
private readonly authenticationService: AuthenticationService,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: 'SuperSecretJWTKey',
});
}
async validate(payload: any, done: Function) {
console.log("I AM HERE"); // this never gets called.
const user = await this.authenticationService.validateUserToken(payload);
if (!user) {
return done(new UnauthorizedException(), false);
}
done(null, user);
}
}
Run Code Online (Sandbox Code Playgroud)
我也试过了ExtractJWT.fromAuthHeaderWithScheme('JWT'),但这不起作用。
authentication.module.ts
@Module({
imports: [
ConfigModule,
UsersModule,
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: 'SuperSecretJWTKey',
signOptions: { expiresIn: 3600 },
}),
],
controllers: [AuthenticationController],
providers: [AuthenticationService, LocalStrategy, JwtStrategy],
exports: [AuthenticationService, LocalStrategy, JwtStrategy],
})
export class AuthenticationModule {}
Run Code Online (Sandbox Code Playgroud)
authentication.controller.ts
@Controller('auth')
export class AuthenticationController {
constructor(
private readonly authenticationService: AuthenticationService,
private readonly usersService: UsersService,
) {}
@UseGuards(AuthGuard('local'))
@Post('login')
public async loginAsync(@Response() res, @Body() login: LoginModel) {
const user = await this.usersService.getUserByUsernameAsync(login.username);
if (!user) {
res.status(HttpStatus.NOT_FOUND).json({
message: 'User Not Found',
});
} else {
const token = this.authenticationService.createToken(user);
return res.status(HttpStatus.OK).json(token);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在 Postman 中,我能够使用我的登录端点以正确的凭据成功登录并接收 JWT 令牌。然后,我Authentication向 GET 请求添加一个标头,复制并粘贴 JWT 令牌,我尝试了“Bearer”和“JWT”方案,并且都返回401 Unauthorized如下图所示。
我使用了 JWT.IO 调试器来检查我的令牌是否有任何问题并且它看起来是正确的:

我不知道这里可能是什么问题。任何帮助将不胜感激。
我遇到过同样的问题。
在我的例子中,问题是验证端点参数位于email和password,
而嵌套身份验证文档指出它们应该是username和 ,password 如下所示:
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
Run Code Online (Sandbox Code Playgroud)
还要注意在请求正文中发送username和。password
学分: https: //github.com/nestjs/docs.nestjs.com/issues/875#issuecomment-619472086
请注意,validate()您的 JWT 策略中的函数仅在成功验证 JWT后才会调用。如果您在尝试使用 JWT 时始终收到 401 响应,那么您不能期望调用此函数。
在return从validate()方法被注入到一个与JWT认证把守的任何操作的请求对象。
我不确定done()您正在调用的函数,但这validate()是我当前项目中的一种工作方法:
async validate(payload: JwtPayload): Promise<User> {
const { email } = payload
const user = await this.authService.getActiveUser(email)
if (!user) {
throw new UnauthorizedException()
}
return user
}
Run Code Online (Sandbox Code Playgroud)
看起来您在返回用户的愿望上走在正确的轨道上。确保这就是authenticationService.validateUserToken()实际所做的。
在策略中,jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()似乎是正确的,并且在 Postman 中使用 Authorization 标头Bearer TOKEN也看起来正确。
关于您的authentication.controller.ts文件,请注意在 NestJS 的控制器中直接使用@Request和@Response对象。这些访问底层框架(例如 Express)并且可能会绕过 Nest 实现的许多功能。请参阅https://docs.nestjs.com/faq/request-lifecycle以查看您要跳过的内容...
您可以直接从NestJS 中的修饰控制器方法(例如@Get()、Post()等)返回对象并抛出错误,框架将负责其余部分:HTTP 代码、JSON 等。
从您的控制器考虑放弃@Reponse res和使用throw new UnauthorizedException('User Not Found')和一个简单return { token }(或类似)的方法来代替。
在您受保护的路线中,我发现明确声明AuthGuard('jwt')效果更好,并且在某些情况下不会产生警告,即使您确实将默认策略设置为 JWT。
你真的需要AuthGuard('local')你的登录路线吗?
在你的loginAsync()方法中不要忘记用你的有效载荷实际签署你的令牌的关键步骤。您没有为createToken()身份验证服务中的方法实现提供代码,但我怀疑这可能是您所缺少的。
考虑登录服务的这个工作实现(它被控制器的登录函数简单地调用):
async login(authCredentialsDto: AuthCredentialsDto): Promise<{ accessToken: string }> {
const { email, password } = authCredentialsDto
const success = await this.usersRepository.verifyCredentials(email, password)
if (!success) {
throw new UnauthorizedException('Invalid credentials')
}
// roles, email, etc can be added to the payload - but don't add sensitive info!
const payload: JwtPayload = { email }
const accessToken = this.jwtService.sign(payload)
this.logger.debug(`Generated JWT token with payload ${JSON.stringify(payload)}`)
return { accessToken }
}
Run Code Online (Sandbox Code Playgroud)
请注意,jwtService通过添加private jwtService: JwtService到构造函数参数,通过依赖注入将 注入到类中。
还要注意上面的接口是如何定义的,JwtPayload所以它是显式类型的。这比any在代码中使用更好。
最后,如果您的 JWT 仍未通过验证,请务必确保您在 Postman 中正确使用了您的令牌。要非常小心,你不加前导/尾随空格,换行,等我犯这个错误我自己。您可能希望通过编写一个快速的 JS 文件来尝试您的 API 并发出一个将 Authorization 标头设置为 value 的获取请求来进行完整性检查Bearer ${token}。
我希望这会有所帮助,祝你好运!
小智 5
我的问题是,我使用 RS256 算法对 JWT 进行签名,并且出现“算法无效”错误。
所以我将其添加"RS256"到我的jwtStrategy构造函数中,现在它看起来像这样:
constructor(private configService: ConfigService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
algorithms:["RS256"],
secretOrKey: configService.get('jwtPublicKey'),
});
}
Run Code Online (Sandbox Code Playgroud)
然后它给了我一个错误,抱怨我的公钥文件上“没有起始行”,错误是我有 ssh-rsa 密钥格式而不是 rsa-pem 格式,我用Get PEM file from ssh-rsa keypair解决了
最后它成功了。
我得到了所有这些信息,在策略输出和防护输出之间放置一个记录器,执行此JWT Auth Guard 示例
| 归档时间: |
|
| 查看次数: |
6494 次 |
| 最近记录: |