似乎没有一种简单的方法可以实现这一点。 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<ConfigAttribute> 的异常。
您的自定义异常可能如下所示:
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')") 对应的ConfigAttribute 是PreInvocationExpressionAttribute,要打印与您想要的内容相似的内容,您可以这样做:
PreInvocationExpressionAttribute attr = (PreInvocationExpressionAttribute)configAttribute;
String expressionString = attr.getAuthorizeExpression().getExpressionString();
System.out.println(expressionString); // "hasAuthority('CUSTOM_AUTHORITY')"
这是主要缺点。此外,您将获得ALLConfigAttributes,不一定是失败的那些。