【问题标题】:Spring boot : How could I customize the forbidden error jsonSpring boot:如何自定义禁止的错误 json
【发布时间】:2019-03-01 20:29:20
【问题描述】:

我想知道是否可以自定义以下禁止的 JSON 错误:

实际反应

{
  "timestamp": "2018-09-26T06:11:05.047+0000",
  "status": 403,
  "error": "Forbidden",
  "message": "Access Denied",
  "path": "/api/rest/hello/me"
}

自定义响应 - 当用户请求没有权限时我得到它。

{ 
  "code": 403,
  "message": "Access denied by the system",
  "status": "Failure"
}

我的网络安全课程

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private JwtTokenProvider jwtTokenProvider;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    http.authorizeRequests()//
        .antMatchers("/rest/hello/signin").permitAll()//
        .anyRequest().authenticated();
    http.apply(new JwtTokenFilterConfigurer(jwtTokenProvider));
  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(12);
  }
}

【问题讨论】:

标签: java spring-boot spring-security jwt


【解决方案1】:

将此添加到您的控制器或 ExceptionHandler 中:

    @ExceptionHandler(AccessDeniedException.class)
    public @ResponseBody ResponseEntity<AuthzErrorResponse> handlerAccessDeniedException(final Exception ex,
            final HttpServletRequest request, final HttpServletResponse response) {

        AuthzErrorResponse authzErrorResponse = new AuthzErrorResponse();
        authzErrorResponse.setMessage("Access denied");

        return new ResponseEntity<>(authzErrorResponse, HttpStatus.FORBIDDEN);
    }

注意:AuthzErrorResponse 是我要返回的自定义 POJO。

【讨论】:

    【解决方案2】:

    您可以像这样使用Jackson ObjectMapper 创建自定义处理程序:

    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, ex) -> {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    
            ServletOutputStream out = response.getOutputStream();
            new ObjectMapper().writeValue(out, new MyCustomErrorDTO());
            out.flush();
        };
    }
    

    然后像这样配置你的HttpSecurity

    http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
    

    另外,你也可以试试 throw AuthenticationException

    @Bean
    public AuthenticationFailureHandler failureHandler() {
        return (request, response, ex) -> { throw ex; };
    }
    

    并在@RestControllerAdvice处理它们:

    @RestControllerAdvice
    public class AdviseController {
    
        @ExceptionHandler(AuthenticationException.class)
        @ResponseStatus(HttpStatus.FORBIDDEN)
        public MyCustomErrorDTO handleAuthenticationException(AuthenticationException ex) {
            return new MyCustomErrorDTO();
        }
    }
    

    但我不确定它是否会起作用,你可以检查一下。

    【讨论】:

    • AuthenticationFailureHandler如何配置HttpSecurity?
    • 我已经这样指出了:http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
    • http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());将用于 AccessDeniedHandler 以及当我想使用 @RestControllerAdvice 时 http 安全 AuthenticationFailureHandler 怎么样
    • 对不起,我没有仔细阅读您的评论。您可以使用AbstractAuthenticationProcessingFilter 类的自定义扩展并将其设置为http.addFilterBefore(authenticationFilter(), AnonymousAuthenticationFilter.class); 很多代码不适合cmets,但我可以分享我的solution
    【解决方案3】:

    为了显示自定义消息,我为 JWT Security 创建了入口点类 JwtAuthenticationEntryPoint。

    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.web.AuthenticationEntryPoint;
    import org.springframework.stereotype.Component;
    @Component
    public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
    
        private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
    
        @Override
        public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                AuthenticationException e) throws IOException, ServletException {
            logger.error("Responding with unauthorized error. Message - {}", e.getMessage());
            httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
                    "Sorry, You're not authorized to access this resource.");
        }
    }
    

    并作为入口点传递给安全配置,

     @Configuration
     @EnableWebSecurity
     @EnableGlobalMethodSecurity(prePostEnabled = true)
     public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
            @Autowired
            private JwtAuthenticationEntryPoint unauthorizedHandler;
    
            @Override
            protected void configure(HttpSecurity http) throws Exception {
    
                http.csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
                        .antMatchers("auth/singIn" , "auth/singUp/")
                        .permitAll().anyRequest().authenticated();
        }
    }
    

    或者您可以使用@ControllerAdvice 和自定义异常处理来处理自定义或系统异常

    【讨论】:

    • 我收到以下回复,请告知如何自定义并使其如我的问题中发布的那样{“timestamp”:“2018-09-26T07:09:56.601+0000”,“status”: 403, "error": "Forbidden", "message": "对不起,您无权访问该资源。", "path": "/api/rest/hello/me" }
    • 据我所知,当用户不允许访问资源时,您想提供自定义消息,在我的示例中,我通过入口点类对其进行自定义,并给出响应消息为“抱歉,您无权访问访问此资源。” , 比如:{ "timestamp": 1537943752965, "status": 401, "error": "Unauthorized", "message": "Sorry, You are not authorized to access this resource.", "path": "/api /report/dateWiseQtyUsedByItemGroupAndItemReport" }
    • 我需要如下自定义消息 { "code": 403, "message": "Access denied by the system", "status": "Failure" }
    • @BhartiLadumor 的答案是正确的,但目前看来,Spring 不再将 message 属性作为错误响应正文的一部分发送,因为我目前正面临这个问题。你有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-05
    • 2021-09-04
    • 2014-12-01
    • 2016-03-31
    • 2014-11-30
    • 2018-02-11
    • 2021-09-25
    相关资源
    最近更新 更多