postman 未处理我的身份验证异常

pokxtpni  于 2022-11-07  发布在  Postman
关注(0)|答案(1)|浏览(309)

我目前正在尝试创建一个全栈应用程序,使用Angular 14和 Spring Boot ,我是带身份验证的堆栈。我的问题是,我使用自己的表单从用户那里获取密码和用户名,然后尝试在后端进行身份验证,我创建了一个身份验证过滤器,在其中我覆盖了attemptAuthentication()方法,该方法接收包含用户名和密码的JSON对象,然后我测试用户名是否存在如果不存在,我抛出UserNotFoundException,如果密码是错误的我抛出BadCredentialsException然后如果一切顺利我返回一个身份验证对象,方法如下:

@Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//        JSON body authentication
        try {
            System.err.println("attempting authentication");
            LoginBody loginBody = new ObjectMapper().readValue(request.getInputStream(), LoginBody.class);
            AppUser user = this.userService.loadUserByUsername(loginBody.getUsername());
            if (user == null) {
                throw new UserNotFoundException("No user with this username") {
                };
            }
            if ( user.getPassword().equals(passwordEncoder.encode(loginBody.getPassword()))) {
                throw new BadCredentialsException("Bad credentials") {
                };
            }
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginBody.getUsername(),loginBody.getPassword()));
        } catch (Exception e) {
            System.err.println(e.getMessage());
            throw new AuthenticationException(e.getMessage()) {
            } ;
        }

我已经创建了一个异常处理程序,它可以很好地用于具有端点/api/...的控制器方法,但不适用于具有端点/auth/login的身份验证,它返回的只是HTTP状态403(禁止),如图所示

这是我的异常处理程序类

package com.webapps.Focus.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class UserExceptionController {

    @ExceptionHandler(value = UserNotFoundException.class)
    public ResponseEntity<Object> exception(UserNotFoundException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(value = BadCredentialsException.class)
    public ResponseEntity<Object> exception(BadCredentialsException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }

}

谢谢你的帮助。

roejwanj

roejwanj1#

根据this article,Exceptionhandler不处理Spring安全异常(如AuthenticationException),因此除了UNAUTHORIZED状态之外,不会显示任何内容作为答案。一个解决方案是为AuthenticationFailureHandler接口创建一个自定义实现,然后覆盖onAuthenticationFailureonAuthenticationFailure()方法,在该方法中,您使用自己的异常处理,如以下示例所示:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Component("userAuthFailureHandler")
public class UserAuthenticationFailureHandler implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException exception)
                                        throws IOException, ServletException {
        try {
            Map<String, String> status = new HashMap<>();
            status.put("status", HttpStatus.UNAUTHORIZED.toString());
            status.put("value", HttpStatus.UNAUTHORIZED.value() + "");
            status.put("reason", HttpStatus.UNAUTHORIZED.getReasonPhrase());
            status.put("error", exception.getMessage());
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            new ObjectMapper().writeValue(response.getOutputStream(), status);
        }catch (Exception e) {
            throw e;
        }
    }

}

然后,在SecurityConfig类中,考虑使用限定符(“userAuthFailureHandler”)注入一个Bean,然后将AuthenticationFilter的AuthenticationFailureHandler属性设置为该Bean:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   ...

    private AuthenticationFailureHandler failureHandler;

    private AuthenticationEntryPoint authEntryPoint;
    public SecurityConfig(...
                          @Qualifier("delegatedAuthenticationEntryPoint") AuthenticationEntryPoint authEntryPoint,
                          @Qualifier("userAuthFailureHandler")AuthenticationFailureHandler failureHandler) {

       ...

        this.authEntryPoint = authEntryPoint;
        this.failureHandler = failureHandler;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
//      configure the stateless authentication
        http.csrf().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

...

        JWTAuthenticationFilter authenticationFilter = new JWTAuthenticationFilter(authenticationManagerBean(), userService, passwordEncoder);
        authenticationFilter.setFilterProcessesUrl("/auth/login");
        authenticationFilter.setAuthenticationFailureHandler(this.failureHandler);
        http.addFilter(authenticationFilter);
        http.addFilterBefore(new JWTAuthorisationFilter(), UsernamePasswordAuthenticationFilter.class);

//        allow security exceptions handling to component with qualifier delegatedAuthenticationEntryPoint
        http.exceptionHandling().authenticationEntryPoint(authEntryPoint);

    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

然后将安全异常处理委托给您的AuthenticationEntryPoint的ow实现,如下所示

//This class will help handle security exceptions that couldn't be handled by ControllerAdvice
@Component("delegatedAuthenticationEntryPoint")
public class DelegatedAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private HandlerExceptionResolver resolver;

    public DelegatedAuthenticationEntryPoint(  @Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
        this.resolver = resolver;
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        resolver.resolveException(request, response, null, authException);
    }

}

相关问题