在 Passport-ActiveDirectory 验证功能中处理错误的密码或用户名

问题描述 投票:0回答:1

我正在使用 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;
  }
}

当用户输入正确的用户名和密码时,我会输出到日志和用户的响应,但是当用户名或密码无效时,我只会得到未经授权的响应。

如何重构验证函数以在用户名或密码无效时显示自定义错误

node.js express active-directory nestjs passport.js
1个回答
0
投票

您可以尝试以下方法:

  1. 添加自定义错误处理逻辑:
async validate(payload: any) {
  if (!payload) {
    throw new UnauthorizedException('Invalid username or password');
  }
  return payload.displayName;
}
  1. 在 API 中的
    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;
  }
}

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.