【问题标题】:PreAuthorize error handling预授权错误处理
【发布时间】:2015-04-09 05:55:27
【问题描述】:

我正在使用 Spring Oauth2Spring Pre-post AnnotationsSpring-boot

我有一个服务类MyServiceMyService 方法之一是:

@PreAuthorize("#id.equals(authentication.principal.id)")
public SomeResponse getExampleResponse(String id){...}

我可以以某种方式控制调用者控制器返回的 json 吗?

默认返回的json是:

{error : "access_denied" , error_message: ".."}

我希望能够控制error_message 参数。我正在寻找类似的东西:

@PreAuthorize(value ="#id.equals(authentication.principal.id)", onError ="throw new SomeException("bad params")")
public SomeResponse getExampleResponse(String id){...}

我想到的一种方法是使用ExceptionHandler

@ExceptionHandler(AccessDeniedException.class)
public Response handleAccessDeniedException(Exception ex, HttpServletRequest request){
    ...
}

但我无法控制异常的message。而且我不能确定这个Exception 是否会在未来的版本中被抛出

【问题讨论】:

  • {error : "access_denied" , error_message: ".."} 看起来像 Spring Boot 默认错误处理程序的输出。你用的是这个吗?
  • 是的 @DaveSyer 我正在使用 Spring 启动

标签: spring spring-security spring-boot spring-annotations spring-security-oauth2


【解决方案1】:

有关错误处理的 Spring Boot 文档:http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling。控制 JSON 的一种方法是添加 @Bean 类型为 ErrorAttributes

@Bean
ErrorAttributes errorAttributes() {
    return new MyErrorAttributes();
}

【讨论】:

  • 感谢您的回答。文档部分不是很清楚,如果有一个关于这个主题的How To 会很棒。 DefaultErrorAttributes 方法:addErrorDetail 我如何控制传递给ErrorAttributesThrowable error 消息?
  • 如果异常来自@PreAuthorize,您将无法控制太多(或者至少我不明白您为什么要这样做)。我想你可以做的是添加一个自定义AccessDecisionManager,但这真的不是很主流。
  • 嗨@DaveSyer,我遇到@PreAuthorize("isAuthenticated() and principal.user.isEnabled() == true and principal.user.isConfirmed() == true") 的情况,我想区分哪些约束会引发AccessDeniedException。然后根据不满意的情况处理它并抛出我自己的异常。或者只有我能做的就是编写自己的方面并自己抛出异常?
  • @royB 您找到原始问题的答案了吗?我和你有完全相同的问题,即我想根据不同的条件抛出不同的异常......
  • @DaveSyer。根据不同条件抛出不同异常的唯一方法是否意味着实现AccessDecisionManager?假设如果预授权中的条件不匹配,我想抛出自定义 PaymentRequiredException 而不是普通的 AccessDeniedException。有没有办法用 Spring boot 和 spring security 的当前实现来做到这一点?
【解决方案2】:

实现 AccessDeniedHandler

@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
        AccessDeniedException accessDeniedException) throws IOException, ServletException {
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    try {
        ObjectMapper mapper = new ObjectMapper();
        SomeJsonModel jsonResponse =new SomeJsonModel();
        mapper.writeValue(response.getOutputStream(), jsonResponse);
    } catch (Exception e) {
        throw new ServletException();
    }
}

SomeJsonModel 将是您自己的 POJO/模型类,您可以控制它 并在资源服务器配置中添加拒绝访问处理程序

@Override
public void configure(HttpSecurity http) throws Exception {
        http.requestMatchers()
                .antMatchers(SECURED_PATTERN).and().authorizeRequests()
                .antMatchers(HttpMethod.POST,SECURED_PATTERN).access(SECURED_WRITE_SCOPE)
                .anyRequest().access(SECURED_READ_SCOPE).and()
              .exceptionHandling().authenticationEntryPoint(newAuthExceptionEntryPoint())
                .accessDeniedHandler(new MyAccessDeniedHandler());
}

【讨论】:

    【解决方案3】:

    当我实现 AccessDeniedHandler 时,它对我不起作用。所以我在 AuthenticationEntryPoint 中创建了一个 ExceptionHandler 函数并将该类标记为 @ControllerAdvice。

    请在下面找到代码

    @ControllerAdvice
    @Component  
    public class EmrExceptionHandler implements AuthenticationEntryPoint {
    
    
        private static final Logger logger = LoggerFactory.getLogger(EmrExceptionHandler.class);
    
        @Override
        public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                             AuthenticationException authException) throws IOException, ServletException {
            logger.error("Unauthorized error: {}", authException.getMessage());
            httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
            httpServletResponse.getWriter().write(convertObjectToJson(new ErrorResponse(ResponseMessages.NOT_AUTHORIZED)));
        }
    
        @ExceptionHandler(value = {AccessDeniedException.class})
        public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                             AccessDeniedException accessDeniedException) throws IOException {
            logger.error("AccessDenied error: {}", accessDeniedException.getMessage());
            httpServletResponse.setStatus(HttpStatus.FORBIDDEN.value());
            httpServletResponse.getWriter().write(convertObjectToJson(new ErrorResponse(ResponseMessages.NOT_PERMITTED)));
        }
    
    
        public String convertObjectToJson(Object object) throws JsonProcessingException {
            if (object == null) {
                return null;
            }
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(object);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-01-31
      • 2018-09-05
      • 2022-12-10
      • 2018-09-11
      • 2020-05-13
      • 2017-12-23
      • 2013-09-11
      • 1970-01-01
      • 2021-02-15
      相关资源
      最近更新 更多