Passport集成NestJS登录功能异常,寻求技术协助
问题描述
登录接口返回如下响应:
{ "message": "Unauthorized", "statusCode": 401 }
控制台日志包含两个关键错误:
UnauthorizedException: Unauthorized,触发自LocalStrategy的验证流程Failed to serialize user into session,触发自SessionSerializer的序列化操作
当前使用的登录请求体:
{ "email ": "email@ygmail.cddqzoem", "password": "OUIOUIOUdzdqI" }
问题根源
1. 请求体字段名不匹配
请求体中使用了带空格的"email "作为字段名,但LocalStrategy配置的usernameField: 'email'会查找无空格的email字段,导致无法获取正确的邮箱值,进而在AuthService中查询不到用户。
2. AuthService验证逻辑顺序错误
validateUser方法中先执行了bcrypt.compare密码验证,再检查用户是否存在。如果用户不存在,user.password会触发Cannot read properties of undefined错误,后续异常处理无法正常执行,最终导致LocalStrategy抛出UnauthorizedException。
3. 序列化错误的连锁反应
由于前面的验证失败,req.user为undefined,super.logIn(request)尝试序列化undefined用户,引发Failed to serialize user into session错误。
修复步骤
步骤1:修正请求体字段名
将请求体中的"email "改为"email",确保字段名与LocalStrategy配置一致:
{ "email": "email@ygmail.cddqzoem", "password": "OUIOUIOUdzdqI" }
步骤2:调整AuthService的验证逻辑顺序
修改auth.service.ts中的validateUser方法,先检查用户是否存在,再执行密码验证:
import { Injectable, NotAcceptableException } from '@nestjs/common'; import { UsersService } from '../users/users.service'; import * as bcrypt from 'bcrypt'; @Injectable() export class AuthService { constructor(private readonly usersService: UsersService) {} async validateUser(email: string, password: string): Promise<any> { // 先查询用户是否存在 const user = await this.usersService.findByEmail(email); if (!user) { throw new NotAcceptableException('could not find the user'); } // 再验证密码正确性 const passwordValid: boolean = await bcrypt.compare(password, user.password); if (!passwordValid) { throw new NotAcceptableException('password is not valid'); } // 返回脱敏后的用户信息 return { userId: user._id, email: user.email, }; } }
步骤3:优化LocalAuthGuard逻辑
确保只有验证成功时才执行登录会话操作,避免序列化undefined用户:
import { ExecutionContext, Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @Injectable() export class LocalAuthGuard extends AuthGuard('local') { async canActivate(context: ExecutionContext) { const result = (await super.canActivate(context)) as boolean; if (result) { const request = context.switchToHttp().getRequest(); await super.logIn(request); } return result; } }
验证修复
完成上述修改后,使用正确的请求体调用登录接口,应正常返回用户信息和成功提示,控制台不再出现错误日志。
内容的提问来源于stack exchange,提问作者Alexscdt
相关产品推荐
相关产品推荐

