我正在按照这篇文章在NestJS中实现JWT身份验证和基于角色的授权
当我注册并登录时,它可以工作,我得到access_token
,但是当我尝试使用令牌进行身份验证时,我总是得到
401 Unauthorized
。
应用程序控制器
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,
};
}
}
我的后端项目几周前曾经完美地工作,但现在它不再工作了。
我不知道这段代码有什么问题,因为从那时起我没有进行任何更改。如果您需要更多信息,请告诉我。
提前谢谢您。
虽然我使用相同的方法使用
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
。