当使用电子邮件进行身份验证时,NestJS护照身份验证返回401



我遇到了一个问题,这个问题似乎并不罕见,但我找到的解决方案在我的项目中不起作用。

正如本教程所建议的那样,我想做的是使用passport进行简单的身份验证:https://docs.nestjs.com/techniques/authentication

我一直遵循这个教程,一开始它很管用。后来我决定使用用户电子邮件和密码作为身份验证,而不是用户名。因此,我将身份验证过程中的变量名和参数更改为电子邮件,这就是一切崩溃的原因。我是不是遗漏了什么?

auth.module.ts

import {Module} from '@nestjs/common';
import {UsersModule} from "../users/users.module";
import {AuthService} from "./services/auth.service";
import {PassportModule} from "@nestjs/passport";
import {LocalStrategy} from "./strategies/local.strategy";
import {AuthController} from "./controllers/auth.controller";
import {JwtModule} from "@nestjs/jwt";
import {jwtConstants} from "./constants";
import {JwtStrategy} from "./strategies/jwt.strategy";
import {EncryptionModule} from "../encryption/encryption.module";
@Module({
imports: [
UsersModule,
EncryptionModule,
PassportModule.register({defaultStrategy: 'jwt'}),
JwtModule.register({
secret: jwtConstants.secret,
signOptions: {
expiresIn: '30s'
}
})
],
providers: [
AuthService,
LocalStrategy,
JwtStrategy
],
controllers: [
AuthController
]
})
export class AuthModule {
}

控制器/auth.controller.ts

import {Controller, Get, Post, Request, UseGuards} from '@nestjs/common';
import {AuthService} from "../services/auth.service";
import {JwtAuthGuard} from "../guards/jwt-auth.guard";
import {LocalAuthGuard} from "../guards/local-auth.guard";
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {
}
@UseGuards(LocalAuthGuard)
@Post('login')
login(@Request() req) {
return this.authService.login(req.user);
}
@UseGuards(JwtAuthGuard)
@Get('profile')
getProfile(@Request() req) {
return req.user;
}
}

services/auth.service.ts

import {Injectable} from '@nestjs/common';
import {UsersService} from "../../users/services/users.service";
import {User} from "../../users/interfaces/user.interface";
import {JwtService} from "@nestjs/jwt";
import {JwtPayloadDto} from "../models/jwt-payload.dto";
import {EncryptionService} from "../../encryption/services/encryption.service";
@Injectable()
export class AuthService {
constructor(private usersService: UsersService,
private jwtService: JwtService,
private encryptionService: EncryptionService) {
}
async validateUser(email: string, pass: string): Promise<User | undefined> {
/**
* The findOne-method sends a database query
* to my mongodb via mongoose.
* I don't think it's necessary to post the UserService here, is it?
*/
const user: User = await this.usersService.findOne(email);
return this.encryptionService.compare(pass, user.password).then((result) => {
if (result) {
return user;
}
return undefined;
});
}
async login(user: User) {
const payload: JwtPayloadDto = {
email: user.email,
sub: user.id
}
return {
accessToken: this.jwtService.sign(payload)
};
}
}

策略/本地策略.ts

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

guards/local-auth.guard.ts

import {Injectable} from "@nestjs/common";
import {AuthGuard} from "@nestjs/passport";
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
}

根据这个问题,我发现验证方法签名必须具有与请求有效载荷密钥相同的参数名称。

出于调试目的,我在strategies/local.strategy.ts中的validate方法的第一行上放置了一个console.log()-调用,但它似乎根本没有被调用。

谢谢你提前回答。祝你好运!

对我来说,在创建LocalStrategy时,我将{usernameField: 'email'}传递给了ParentClass。

如果你想用"电子邮件"之类的自定义列检查用户身份验证,请尝试通过。

我的user.entity.ts:

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
email: string;
@Column()
name: string;
}

我的本地战略:

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({ usernameField: 'email' });
}
async validate(email: string, password: string): Promise<User> {
console.log(email, password); // it works
}
}

好吧,我自己解决了。浪费了5个小时的调试时间!结果发现,不知怎么的,我的邮差并没有将Content-Type标头与请求一起发送。重新启动Postman修复了它。

最新更新