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

Max*_*Max 7 authentication passport-local passport.js nestjs

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

我想做的是使用护照进行简单的身份验证,如本教程所示: 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 {
}
Run Code Online (Sandbox Code Playgroud)

控制器/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;
    }
}
Run Code Online (Sandbox Code Playgroud)

服务/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)
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

策略/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;
    }
}
Run Code Online (Sandbox Code Playgroud)

守卫/local-auth.guard.ts

import {Injectable} from "@nestjs/common";
import {AuthGuard} from "@nestjs/passport";

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
}
Run Code Online (Sandbox Code Playgroud)

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

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

感谢您提前的任何答复。祝你有个好的一天!

blu*_*ope 20

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

如果您想使用“电子邮件”等自定义列检查用户身份验证,请尝试通过它。

我的用户.entity.ts:

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  name: string;
}
Run Code Online (Sandbox Code Playgroud)

我的 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
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我花了5个小时来解决这个问题!谢谢 ! (2认同)

Max*_*Max 2

嗯,我自己解决了。浪费了5个小时的调试!事实证明,不知何故,我的邮递员没有随请求发送 Content-Type 标头。重新启动邮差修复了它。