简体   繁体   English

Springboot 中的授权失败返回带有 403 状态消息的空体

[英]Authorization failure in Springboot returns empty body with 403 status message

I have implemented a custom exception handler that handles all the exception that I am throwing:我已经实现了一个自定义异常处理程序来处理我抛出的所有异常:

@ControllerAdvice
public class AppExceptionHandler {
    

    @ExceptionHandler(value = {UserServiceException.class})
    public ResponseEntity<Object>handleUserServiceException(
                            UserServiceException ex, WebRequest request){
        
        ErrorMessage errorMessage = new ErrorMessage(new Date(), ex.getMessage());
        
        return new ResponseEntity<>(errorMessage, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR );
    }
    
    //A universal exception handling method
    @ExceptionHandler(value = {Exception.class})
    public ResponseEntity<Object>handleUserOtherExceptions(Exception ex, WebRequest request){
        
        ErrorMessage errorMessage = new ErrorMessage(new Date(), ex.getMessage());
        
        return new ResponseEntity<>(errorMessage, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR );
    }

}

The Universal exception handler method doesn't gets called for 403 status response, the response body is empty but I want to see a response body.不会为 403 状态响应调用通用异常处理程序方法,响应主体为空,但我想查看响应主体。

Below is my Security class:下面是我的安全 class:

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter{
    
    private final UserService userService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;
//  @Autowired
//  AuthenticationFailureHandler authenticationFailureHandler;
    
    public WebSecurity(UserService userService, BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.userService = userService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
        .antMatchers(HttpMethod.POST, SecurityConstants.SIGN_UP_URL)
        .permitAll()
        .anyRequest()
        .authenticated()
        .and()
        .addFilter(getAuthenticationFilter())
        .addFilter(new AuthorizationFilter(authenticationManager()))
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
    
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService)
        .passwordEncoder(bCryptPasswordEncoder);
    }   
    
    public AuthenticationFilter getAuthenticationFilter() throws Exception{
        final AuthenticationFilter filter = new AuthenticationFilter(authenticationManager());
        filter.setFilterProcessesUrl("/users/login");
        return filter;
    }

Below is my AuthenticationFilter:下面是我的 AuthenticationFilter:

public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter{
    
    private final AuthenticationManager authenticationManager;
    
    public AuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }
    
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException {
        
        try {
            UserLoginRequestModel creds = new ObjectMapper()
                    .readValue(req.getInputStream(), UserLoginRequestModel.class);
            
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            creds.getEmail(), creds.getPassword(), new ArrayList<>()));
            
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
        
    }
    
    @Override
    protected void successfulAuthentication(HttpServletRequest req
            , HttpServletResponse res
            , FilterChain chain
            , Authentication auth)
            throws IOException, ServletException {
        
        String userName = ((User) auth.getPrincipal()).getUsername();
        String token = Jwts.builder()
                .setSubject(userName)
                .setExpiration(new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SecurityConstants.getTokenSecret())
                .compact();
        
        UserService userService = (UserService) SpringApplicationContext.getBean("userServiceImpl");
        UserDto userDto = userService.getUser(userName);
        
        res.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
        res.addHeader(SecurityConstants.USER_ID, userDto.getUserId());
    }
}

Below is my AuthorizationFilter:下面是我的 AuthorizationFilter:

public class AuthorizationFilter extends BasicAuthenticationFilter {

    public AuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String header = request.getHeader(SecurityConstants.HEADER_STRING);
        
        if(header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            chain.doFilter(request, response);
            return;
        }
        
        UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }
    
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(SecurityConstants.HEADER_STRING);
        
        if(token != null) {
            token = token.replace(SecurityConstants.TOKEN_PREFIX, "");
            
            String user = Jwts.parser()
                    .setSigningKey(SecurityConstants.getTokenSecret())
                    .parseClaimsJws(token)
                    .getBody()
                    .getSubject();
            
            if(user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
            }       
        }
        
        return null;
    }
}

Below is my postman response (As you can see the body is empty以下是我的 postman 回复(如您所见,正文是空的在此处输入图像描述

I want Spring to handle all other exceptions by calling the overriding @ExceptionHandler I have written in the above AppExceptionHandler class.我希望 Spring 通过调用我在上面的AppExceptionHandler @ExceptionHandler中编写的覆盖 @ExceptionHandler 来处理所有其他异常。

As you can see the response body is empty.如您所见,响应主体是空的。 How do I return the default or custom object for response body?如何返回响应正文的默认或自定义 object?

Im not quite sure if this is what you are looking for, but If you want to somehow customize the messages from failed authentication have a look on AuthenticationEntryPoint like in https://www.baeldung.com/spring-security-basic-authentication .我不太确定这是否是您要查找的内容,但是如果您想以某种方式自定义来自失败身份验证的消息,请查看AuthenticationEntryPoint ,例如https://www.baeldung.com/spring-security-basic-authentication There you can react on the thrown exception and customize what message and codes to return.在那里您可以对抛出的异常做出反应并自定义要返回的消息和代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM