NestJS使用passport-local验证时合法用户仍返回401(Unauthorized)求助
NestJS passport-local 身份认证返回401未授权问题
我按照教程在NestJS中基于passport-local实现身份认证,但使用合法用户请求时始终返回401错误,找不到问题所在。
代码结构
- 认证模块结构:

- 用户模块结构:

代码详情
认证模块
authentication.module.ts
import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; import { UserModule } from 'src/user/user.module'; import { AuthenticationController } from './controllers/authentication.controller'; import { AuthenticationService } from './services/authentication.service'; import { LocalStrategy } from './strategies/local.strategy'; @Module({ imports:[UserModule, PassportModule], controllers: [AuthenticationController], providers: [AuthenticationService, LocalStrategy] }) export class AuthenticationModule {}
authentication.controller.ts
import { Controller, Post, Request, UseGuards } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { UserService } from 'src/user/services/user.service'; @Controller('authentication') export class AuthenticationController { constructor(private userService: UserService){} @UseGuards(AuthGuard('local')) @Post('signin') async signin(@Request() req){ return req.user; } }
authentication.service.ts
import { Injectable } from '@nestjs/common'; import { UserService } from 'src/user/services/user.service'; @Injectable() export class AuthenticationService { constructor(private userService: UserService) {} async validateUser(email: string, password: string): Promise<any> { const user = await this.userService.readUserByEmail(email); if (user && user.password === password) { const { password, ...result } = user; return result; } return null; } }
local.strategy.ts
import { Injectable, UnauthorizedException } from "@nestjs/common"; import { PassportStrategy } from "@nestjs/passport"; import { Strategy } from "passport-local"; import { AuthenticationService } from "../services/authentication.service"; @Injectable() export class LocalStrategy extends PassportStrategy(Strategy){ constructor(private authenticationService: AuthenticationService){ super(); } async validate(username: string, password: string): Promise<any> { const user = await this.authenticationService.validateUser(username, password); if (!user) { throw new UnauthorizedException(); } return user; } }
用户模块
user.module.ts
import { Module } from '@nestjs/common'; import { UserController } from './controllers/user.controller'; import { UserService } from './services/user.service'; @Module({ controllers: [UserController], providers: [UserService], exports: [UserService] }) export class UserModule {}
user.service.ts
import { Injectable } from '@nestjs/common'; import { prisma } from 'src/main'; import { CreateUserDTO } from '../dto/create-user.dto'; import { UpdateUserDTO } from '../dto/update-user.dto'; @Injectable() export class UserService { private readonly users = [ { id: "1", name: "Ajitesh", email: "ajitesh@example.com", password: "secret" } ] //....其他方法 async readUserByEmail(email: string){ return this.users.find(user => user.email === email); } }
请求示例
{ "email": "ajitesh@example.com", "password": "secret" }
问题原因及解决方法
passport-local 默认会从请求体中读取username和password字段,但你的请求传的是email和password,导致策略无法正确获取邮箱参数,验证失败返回401。
解决步骤:
- 在
LocalStrategy的构造函数中,通过super()配置自定义字段名,将用户名字段指定为email:
constructor(private authenticationService: AuthenticationService){ super({ usernameField: 'email' }); }
- 可选:将
validate方法的第一个参数名改为email,语义更清晰:
async validate(email: string, password: string): Promise<any> { const user = await this.authenticationService.validateUser(email, password); if (!user) { throw new UnauthorizedException(); } return user; }
修改后,passport-local就能正确读取请求体中的email字段完成用户验证。
内容的提问来源于stack exchange,提问作者Ajitesh Sivakumar
相关产品推荐
相关产品推荐

