【问题标题】:Return 404 instead of 403 when @PostAuthorize fails@PostAuthorize 失败时返回 404 而不是 403
【发布时间】:2020-03-23 10:30:13
【问题描述】:

假设我有以下控制器。 (假设Order.customer 是订单所属的客户,并且只有他们应该能够访问它。)

@RestController
@RequestMapping("/orders")
public class OrderController {
    @GetMapping
    @PostAuthorize("returnObject.customer == authentication.principal")
    public Order getOrderById(long id) {
        /* Look up the order and return it */
    }
}

查找订单后,@PostAuthorize 用于确保它属于经过身份验证的客户。如果不是,Spring 会以 403 Forbidden 响应。

这样的实现有一个问题:客户可以区分不存在的订单和他们无权访问的订单。理想情况下,在这两种情况下都应该返回 404。

虽然这可以通过将Authentication 注入处理程序方法并在那里实现自定义逻辑来解决,但有没有办法使用@PostAuthorize 或类似的声明性API 来实现?

【问题讨论】:

    标签: java spring spring-security


    【解决方案1】:

    您可以尝试使用 ControllerAdvice 来捕获并转换 PostAuthorize 抛出的 AccessDeniedException。

    @RestControllerAdvice
    public class ExceptionHandlerController {
    
        @ResponseStatus(HttpStatus.NOT_FOUND)
        @ExceptionHandler(AccessDeniedException.class)
        public String handleAccessDenied(AccessDeniedException e) {
            return "nothing here"; // or a proper object
        }
    }
    

    【讨论】:

      【解决方案2】:

      您可以在 Spring Security 配置中指定自定义 AccessDeniedHandler
      在以下示例中,处理程序将在访问被拒绝失败时返回 404 Not Found。

      @EnableWebSecurity
      public class SecurityConfig extends WebSecurityConfigurerAdapter {
      
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                      // ...
                      .exceptionHandling(exceptionHandling -> exceptionHandling
                              .accessDeniedHandler(accessDeniedHandler())
                      );
          }
      
          @Bean
          public AccessDeniedHandler accessDeniedHandler() {
              return new CustomAccessDeniedHandler();
          }
      }
      
      public class CustomAccessDeniedHandler implements AccessDeniedHandler {
          @Override
          public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
              response.sendError(HttpStatus.NOT_FOUND.value(), HttpStatus.NOT_FOUND.getReasonPhrase());
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2018-12-05
        • 2019-09-18
        • 1970-01-01
        • 1970-01-01
        • 2011-12-18
        • 1970-01-01
        • 2018-07-31
        • 2019-06-24
        • 2010-12-01
        相关资源
        最近更新 更多