使用电子邮件进行身份验证时,NestJS 护照身份验证返回 401
Posted
技术标签:
【中文标题】使用电子邮件进行身份验证时,NestJS 护照身份验证返回 401【英文标题】:NestJS passport authentication returns 401 when using email for authentication 【发布时间】:2020-07-18 21:15:03 【问题描述】:我有一个似乎并不罕见的问题,但我找到的解决方案在我的项目中不起作用。
我想要做的是使用本教程建议的简单身份验证: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;
服务/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)
;
策略/local.strategy.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;
守卫/local-auth.guard.ts
import Injectable from "@nestjs/common";
import AuthGuard from "@nestjs/passport";
@Injectable()
export class LocalAuthGuard extends AuthGuard('local')
根据this question,我发现 validate-methods 签名必须与请求有效负载密钥具有相同的参数名称。
出于调试目的,我在strategies/local.strategy.ts
的验证方法的第一行放置了一个console.log()
-call,但它似乎根本没有被调用。
感谢您提前回答。 祝你好运!
【问题讨论】:
我需要更正最后一部分。我误读了。validate
-方法的签名必须是精确的用户名和密码。我将方法中的那部分改回原来的样子,但它仍然无法正常工作。
【参考方案1】:
对我来说,在创建 LocalStrategy 时,我将 usernameField: 'email'
传递给了 ParentClass。
如果您想使用“电子邮件”等自定义列检查用户身份验证,请尝试通过它。
我的 user.entity.ts:
@Entity()
export class User
@PrimaryGeneratedColumn()
id: number;
@Column( unique: true )
email: string;
@Column()
name: string;
我的 local.strategy.ts:
@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 个小时!谢谢!【参考方案2】:嗯,我自己解决了。 5个小时的调试浪费了! 原来,不知何故,我的邮递员没有随请求发送 Content-Type 标头。重新启动 Postman 即可解决。
【讨论】:
以上是关于使用电子邮件进行身份验证时,NestJS 护照身份验证返回 401的主要内容,如果未能解决你的问题,请参考以下文章
使用带护照本地的护照Facebook策略时无法将用户序列化到会话中
通过库共享时未注册 NestJS 自定义 PassportStrategy