我正在使用 Nestjs 创建一个 REST API,作为身份验证的一部分,我需要根据我公司的活动目录对用户进行身份验证,我能够使用“passport-activedirectory”策略来对用户进行身份验证,并且工作正常。
我现在面临的问题是,当用户输入错误的用户名密码时,处理后端身份验证的验证函数只会返回 401 未经授权的响应,这是预期的,但我需要能够向前端提供友好的消息用户名或密码不正确。
这是我的 active-directory.strtegy.ts 文件
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import * as Strategy from 'passport-activedirectory';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class ActiveDirectoryStrategy extends PassportStrategy(
Strategy,
'activedirectory',
) {
constructor(configService: ConfigService) {
super({
integrated: false,
ldap: {
url: configService.get<string>('LDAPURL'),
baseDN: configService.get<string>('LDAPBASEDN'),
username: configService.get<string>('LDAPUSERNAME'),
password: configService.get<string>('LDAPPASSWORD'),
},
clientOptions: {
reconnect: true,
},
});
}
async validate(payload: any) {
return payload.displayName;
}
}
我尝试将我的实现包装在
trycatch
中的验证函数中,但仍然不起作用
async validate(payload: any) {
try {
if (!payload) {
throw new UnauthorizedException('Invalid username or password');
}
return payload.displayName;
} catch (error) {
console.error('Authentication failed:', error);
throw new UnauthorizedException('Invalid username or password');
}
}
我还尝试创建一个 Unathourzed 异常过滤器来捕获验证函数中抛出的异常,但似乎不起作用
import {
ExceptionFilter,
Catch,
ArgumentsHost,
UnauthorizedException,
} from '@nestjs/common';
import { Response } from 'express';
@Catch(UnauthorizedException)
export class UnauthorizedExceptionFilter implements ExceptionFilter {
catch(exception: UnauthorizedException, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse<Response>();
const status = exception.getStatus();
const message = exception.message || 'Unauthorized';
response.status(status).json({
statusCode: status,
message: message,
});
}
}
这是我的 auth.controller.ts
import { ApiProperty } from '@nestjs/swagger';
export class SignInResponseData {
@ApiProperty()
access_token: string;
@ApiProperty()
displayName: string;
}
import {
Controller,
Post,
UseGuards,
Body,
HttpCode,
HttpStatus,
Req,
Get,
UnauthorizedException,
} from '@nestjs/common';
import { SignInDto } from './dto/sign-in.dto';
import { Request } from 'express';
import { ApiOkResponse } from '@nestjs/swagger';
import { UserEntity } from 'src/users/entities/user.entity';
import { AuthService } from './auth.service';
import { JwtAuthGuard } from './jwt-auth.guard';
import { ActiveDirectoryAuthGuard } from './active-directory-auth.guard';
@Controller('api/auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@UseGuards(ActiveDirectoryAuthGuard)
@HttpCode(HttpStatus.OK)
@ApiOkResponse({ type: SignInResponseData })
@Post('sign-in')
async signIn(@Body() signInDto: SignInDto, @Req() req: Request) {
console.log(signInDto, req.user);
return req.user;
}
}
当用户输入正确的用户名和密码时,我会输出到日志和用户的响应,但是当用户名或密码无效时,我只会得到未经授权的响应。
如何重构验证函数以在用户名或密码无效时显示自定义错误
您可以尝试以下方法:
async validate(payload: any) {
if (!payload) {
throw new UnauthorizedException('Invalid username or password');
}
return payload.displayName;
}
catch
短语中配置相同的内容:@UseGuards(ActiveDirectoryAuthGuard)
@Post('sign-in')
async signIn(@Body() signInDto: SignInDto, @Req() req: Request) {
try {
return req.user;
} catch (error) {
throw new UnauthorizedException(error.message || 'Invalid credentials');
}
}
针对您的代码,应用以下更改并观察问题是否得到解决:
您的
active-directory.stratrgy.ts
文件:
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import * as Strategy from 'passport-activedirectory';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class ActiveDirectoryStrategy extends PassportStrategy(
Strategy,
'activedirectory',
) {
constructor(configService: ConfigService) {
super({
integrated: false,
ldap: {
url: configService.get<string>('LDAPURL'),
baseDN: configService.get<string>('LDAPBASEDN'),
username: configService.get<string>('LDAPUSERNAME'),
password: configService.get<string>('LDAPPASSWORD'),
},
clientOptions: {
reconnect: true,
},
});
}
// Updated validate function to throw specific error messages
async validate(payload: any) {
if (!payload) {
throw new UnauthorizedException('Invalid username or password');
}
return payload.displayName;
}
}
您的
unauthorized-exception.filter.ts
文件:
import { ExceptionFilter, Catch, ArgumentsHost, UnauthorizedException } from '@nestjs/common';
import { Response } from 'express';
@Catch(UnauthorizedException)
export class UnauthorizedExceptionFilter implements ExceptionFilter {
catch(exception: UnauthorizedException, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse<Response>();
const status = exception.getStatus();
const message = exception.message || 'Unauthorized';
response.status(status).json({
statusCode: status,
message: message,
});
}
}
你的
controller
逻辑应该是这样的:
@Controller('api/auth')
export class AuthController {
@UseGuards(ActiveDirectoryAuthGuard)
@HttpCode(HttpStatus.OK)
@Post('sign-in')
async signIn(@Body() signInDto: SignInDto, @Req() req: Request) {
// If authentication is successful, `req.user` will be populated as configured above
console.log(signInDto, req.user);
return req.user;
}
}
希望这有帮助!