【问题标题】:Spring MVC accessing Spring Security ConfigAttributes?Spring MVC 访问 Spring Security ConfigAttributes?
【发布时间】:2016-12-20 00:24:30
【问题描述】:

除了403 Forbidden HTTP 状态代码之外,我还想生成带有错误消息的 HTTP 响应正文,该消息引用诸如 _"missing ... 'CUSTOM_AUTHORITY'"_ 之类的内容。

我的应用程序是 Spring Boot,在 Spring-MVC-REST @Controller 中使用 Spring-Security-Secured @PreAuthorize 方法:

我的控制器

@Controller
@RequestMapping("/foo")
public FooController{
  @PreAuthorize("hasAuthority('CUSTOM_AUTHORITY')")
  public Object getSomething(){ ... }
}

GlobalExceptionHandlerResolver

@ControllerAdvice
public class GlobalExceptionHandler {
  @ExceptionHandler(AccessDeniedException.class)
  @ResponseStatus(HttpStatus.FORBIDDEN)
  public Object forbidden(AccessDeniedException exception){ ... }
}

想要是暴露/注入Collection<ConfigAttribute>Spring Security docs reference it

【问题讨论】:

    标签: spring spring-mvc spring-security spring-boot


    【解决方案1】:

    似乎没有一种简单的方法可以实现这一点。 AccessDecisionManager(即AffirmativeBased)会抛出AccessDeniedException,但没有您想要的信息。所以如果你想“暴露/注入”Collection<ConfigAttribute>,你需要提供你自己的AccessDecisionManager,它会抛出一个包含ConfigAttributes的自定义异常。

    执行此操作的最简单方法是使用您自己的默认 AccessDecisionManager 包装并委托对它的方法调用:

    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled=true)
    CustomMethodSecurityConfig extends GlobalMethodSecurityConfiguration
    
        @Override
        protected AccessDecisionManager accessDecisionManager() {
            AccessDecisionManager default = super.accessDecisionManager();
            MyCustomDecisionManager custom = new CustomDecisionManager(default);
        }
    }
    

    您可以按如下方式定义您的自定义AccessDecisionManager

    public class MyCustomDecisionManager implements AccessDecisionManager {
    
        private AccessDecisionManager default;
    
        public MyCustomDecisionManager(AccessDecisionManager acm) {
            this.default = acm;
        }
    
        @Override
        public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException{
            try {
                default.decide(authentication, object, configAttributes)
            } catch(AccessDeniedException ex) {
                throw new CustomAccessDeniedException(ex.getMessage(), configAttributes);
            }
        }
    
        // other methods delegate to default
    }
    

    现在,每当访问被拒绝时,您都会收到一个包含 Collection&lt;ConfigAttribute&gt; 的异常。

    您的自定义异常可能如下所示:

    public class CustomAccessDeniedException extends AccessDeniedException {
        private Collection<ConfigAttribute> attributes;
    
        public CustomAccessDeniedException(String message, Collection<ConfigAttribute> attr) {
            super(message);
            this.attributes = attr;
        }
    
        public Collection<ConfigAttribute> getAttributes() {
            return this.attributes;
        }
    }
    

    现在您的@ExceptionHandler 可以处理您的CustomAccessDeniedException 并可以访问ConfigAttributes。

    但是... 我不确定这是否会为您提供所需的错误消息。 ConfigAttribute 接口只有一种方法:

    String getAttribute();
    

    javadoc 声明:

    如果 ConfigAttribute 不能以足够的精度表示为 String,则应返回 null。

    由于我们不能依赖接口方法,你如何处理每个ConfigAttribute 将在很大程度上取决于你正在处理的特定对象的类型。

    例如,与@PreAuthorize("hasAuthority('CUSTOM_AUTHORITY')") 对应的ConfigAttributePreInvocationExpressionAttribute,要打印与您想要的内容相似的内容,您可以这样做:

    PreInvocationExpressionAttribute attr = (PreInvocationExpressionAttribute)configAttribute;
    
    String expressionString = attr.getAuthorizeExpression().getExpressionString();
    
    System.out.println(expressionString); // "hasAuthority('CUSTOM_AUTHORITY')"
    

    这是主要缺点。此外,您将获得ALLConfigAttributes,不一定是失败的那些。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-15
      • 1970-01-01
      • 2017-08-13
      • 2012-12-05
      • 2011-01-08
      • 2016-06-18
      相关资源
      最近更新 更多