我有一个示例类要测试@PreAuthorize
注释,看起来或多或少像这样:
class BankService {
@PreAuthorize("hasCustomRole('ROLE_CUSTOM') or hasRole('ROLE_EXAMPLE')")
Double getAccountBalance(Integer accountNumber) {
return 1234;
}
@PreAuthorize("#accountNumber > 400")
int getValue(Integer accountNumber) {
return 1234;
}
}
你可以注意到hasCustomRole(String expression)
in the @PreAuthorize
注释,我正在添加:
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot {
public CustomSecurityExpressionRoot(Authentication auth) {
super(auth);
}
public boolean hasCustomRole(String expression) {
return /* some magic */;
}
}
另外,我正在延长DefaultMethodSecurityExpressionHandler
通过以下方式:
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
public CustomMethodSecurityExpressionHandler() {
super();
}
@Override
public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi);
ctx.setRootObject(new CustomSecurityExpressionRoot(auth));
return ctx;
}
}
最后,一切都包裹在resources.groovy
:
beans = {
/* ... some stuff ... */
xmlns security:'http://www.springframework.org/schema/security'
security.'global-method-security'('pre-post-annotations': 'enabled') {
security.'expression-handler'(ref: 'expressionHandler')
}
expressionHandler(my.package.plugin.security.expression.CustomMethodSecurityExpressionHandler)
}
现在,如果我从中删除安全部分resources.groovy
,我自然就失去了使用的能力hasCustomRole()
方法,但以下有效:
assert bankService.getValue(500) == 1234
但是如果我注入自己的实现,前面的语句会导致:
Access is denied
org.springframework.security.access.AccessDeniedException: Access is denied
经过进一步调查,我发现了这一点:
prepost.PrePostAnnotationSecurityMetadataSource Looking for Pre/Post annotations for method 'getValue' on target class 'class my.package.plugin.security.test.BankService'
prepost.PrePostAnnotationSecurityMetadataSource @org.springframework.security.access.prepost.PreAuthorize(value=#accountNumber > 400) found on specific method: public int my.package.plugin.security.test.BankService.getValue(java.lang.Integer)
method.DelegatingMethodSecurityMetadataSource Adding security method [CacheKey[my.package.plugin.security.test.BankService; public int my.package.plugin.security.test.BankService.getValue(java.lang.Integer)]] with attributes [[authorize: '#accountNumber > 400', filter: 'null', filterTarget: 'null']]
aopalliance.MethodSecurityInterceptor Secure object: ReflectiveMethodInvocation: public int my.package.plugin.security.test.BankService.getValue(java.lang.Integer); target is of class [my.package.plugin.security.test.BankService$$EnhancerByCGLIB$$c590f9ac]; Attributes: [[authorize: '#accountNumber > 400', filter: 'null', filterTarget: 'null']]
aopalliance.MethodSecurityInterceptor Previously Authenticated: org.springframework.security.authentication.TestingAuthenticationToken@b35bafc3: Principal: test; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_TELLER
method.MethodSecurityEvaluationContext Unable to resolve method parameter names for method: public final int my.package.plugin.security.test.BankService$$EnhancerByCGLIB$$c590f9ac.getValue(java.lang.Integer). Debug symbol information is required if you are using parameter names in expressions.
有趣的部分是Debug symbol information is required if you are using parameter names in expressions.
,这表明编译类时没有有关变量名称的调试信息。但如果我不注入自己的豆子,一切都会正常。
缺少调试信息的原因可能是什么,以及如何修复它?
它是一个 Grails 插件,为 Grails 2.0.4 开发,使用版本 1.2.7.3 的 spring-security-core 插件、版本 1.1 的 spring-security-acl 插件和 Spring Security 3.0.7.RELEASE。
EDIT:
为了让这个问题更有趣,这是我后来发现的:“丢失”的调试信息实际上是存在的,如果你查看一下.class
文件与javap
。所以类被正确编译,但 Spring 仍然抱怨......