NestJS 中使用 JWT 令牌的 Auth Guard 返回 401 未经授权

问题描述 投票:0回答:1

我正在按照这篇文章在NestJS中实现JWT身份验证和基于角色的授权

当我注册并登录时,它可以工作,我得到

access_token

,但是当我尝试使用令牌进行身份验证时,我总是得到 
401 Unauthorized

  • 登录

Login on Postman .png

  • 获取用户

User as Admin authentication on Postman .png

这是我的代码:

应用程序控制器

import { Body, Controller, Get, Post, Request, UseGuards } from '@nestjs/common'; import { AuthService } from './auth/auth.service'; import { SignUpDTO } from './auth/dto/signup.dto'; import { HasRoles } from './auth/roles/has-roles.decorator'; import { Role } from './auth/roles/role.enum'; import { RoleGuard } from './auth/roles/role.guard'; import { JwtAuthGuard } from './auth/strategy/jwt-auth.guard'; import { LocalAuthGuard } from './auth/strategy/local-auth.guard'; import { User } from './user/interfaces/user.interface'; @Controller() export class AppController { constructor(private authService: AuthService) {} @Post('auth/register') async register(@Body() signUpDTO :SignUpDTO): Promise\<User\> { return this.authService.signUp(signUpDTO) } @UseGuards(LocalAuthGuard) @Post('auth/login') async login(@Request() req) { return this.authService.login(req.user); } @UseGuards(JwtAuthGuard) @Get('profile') getAuthJWT(@Request() req) { return req.user; } @HasRoles(Role.USER, Role.SELLER, Role.BUYER) @UseGuards(JwtAuthGuard, RoleGuard) // @UseGuards(JwtAuthGuard) @Get('user') getProfile(@Request() req) { return {data: req.user, messgage: `Welcome ${req.user.roles}`}; } @HasRoles(Role.ADMIN) @UseGuards(JwtAuthGuard, RoleGuard) @Get('admin') async adminOnlyEndpoint(@Request() req) { return {data: req.user, messgage: "Welcome admin"}; } }

auth.module

import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; import { PassportModule } from '@nestjs/passport'; import { UserModule } from 'src/user/user.module'; import { AuthService } from './auth.service'; import { JwtStrategy } from './strategy/jwt.strategy'; import { LocalStrategy } from './strategy/local.strategy'; @Module({ imports: [ UserModule, PassportModule, JwtModule.register({ global: true, secret: `${process.env.JWT_SECRET_KEY}`, signOptions: { expiresIn: '10m'}, }), ], providers: [ AuthService, LocalStrategy, JwtStrategy, ], exports: [AuthService] }) export class AuthModule {}

auth.service

import { Injectable, NotAcceptableException, UnauthorizedException } from '@nestjs/common'; import { User } from 'src/user/interfaces/user.interface'; import { UserService } from 'src/user/user.service'; import { hashPassword } from 'src/_utils/hashPassword'; import { validatePassword } from 'src/_utils/validatePassword'; import { SignUpDTO } from './dto/signup.dto'; import { JwtService } from '@nestjs/jwt'; @Injectable() export class AuthService { constructor( private userService: UserService, private jwtService: JwtService, ) { } async login(user: any) { const payload = { _id: user._id, username: user.username, roles: user.roles, }; return { access_token: this.jwtService.sign(payload), }; } async validateUser(username: string, password: string): Promise<User | null> { const user = await this.userService.getByUsername(username); if (!user) return null; const passwordValid = await validatePassword(password, user.password) if (!user) { throw new NotAcceptableException('could not find the user'); } if (user && passwordValid) { return user; } return null; } async signUp(signupUserDTO: SignUpDTO): Promise<User> { const emailExisting = await this.userService.getByEmail(signupUserDTO.email) const usernameExisting = await this.userService.getByUsername(signupUserDTO.username) const hashedPassword = await hashPassword(signupUserDTO.password); if (emailExisting) { throw new UnauthorizedException(`This email's already existed`); } else if (usernameExisting) { throw new UnauthorizedException(`This username's already existed`); } else return await this.userService.create({ ...signupUserDTO, password: hashedPassword }) } }

本地策略

import { Strategy } from 'passport-local'; import { PassportStrategy } from '@nestjs/passport'; import { Injectable, UnauthorizedException } from '@nestjs/common'; import { AuthService } from '../auth.service'; @Injectable() export class LocalStrategy extends PassportStrategy(Strategy) { constructor(private authService: AuthService) { super(); } async validate(username: string, password: string): Promise<any> { const user = await this.authService.validateUser(username, password); if (!user) { throw new UnauthorizedException(); } return user; } }

jwt.策略

import { ExtractJwt, Strategy } from 'passport-jwt'; import { PassportStrategy } from '@nestjs/passport'; import { Injectable } from '@nestjs/common'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: `${process.env.JWT_SECRET_KEY}`, }); } async validate(payload: any) { return { _id: payload._id, username: payload.username, roles: payload.roles, }; } }
我的后端项目几周前曾经完美地工作,但现在它不再工作了。
我不知道这段代码有什么问题,因为从那时起我没有进行任何更改。

如果您需要更多信息,请告诉我。

提前谢谢您。

authentication jwt nestjs bearer-token passport-jwt
1个回答
0
投票
问题已解决。我已经找到问题的原因了。

虽然我使用相同的方法使用

auth.module.ts

 将 JWT 密钥导入到我的 
jwt.strategy.ts
${process.env.JWT_SECRET_KEY}
 文件中,但值并不相等。结果,我的 JWTGuard 无法正确提取令牌,从而导致 401 未经授权的响应。”

要访问

.env

 文件中的值,我使用具有 
.get()
 方法的 ConfigService。为了导入 JWT 模块,我使用了工厂函数技术并传递了一个异步配置,而不是 
auth.module.ts
 处的普通配置。我还将 
ConfigService
 注入 JWTStrategy 的 
jwt.strategy.ts

© www.soinside.com 2019 - 2024. All rights reserved.