【发布时间】:2012-11-15 06:24:33
【问题描述】:
我有一个示例类来测试@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;
}
}
您可以在@PreAuthorize 注释中注意到hasCustomRole(String expression),这是我添加的:
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.,它表明编译类时没有关于变量名的调试信息。但是,如果我不注入自己的 bean,一切都会正常工作。
缺少调试信息的原因可能是什么,以及如何解决?
这是一个 Grails 插件,为 Grails 2.0.4 开发,使用版本 1.2.7.3 的 spring-security-core 插件、版本 1.1 的 spring-security-acl 插件和 Spring Security 3.0.7.RELEASE。
编辑:
为了让这个问题更有趣,这就是我后来发现的:如果你用javap 查看.class 文件,“缺失”的调试信息实际上就在那里。所以类被正确编译了,但是 Spring 还是会抱怨......
【问题讨论】:
标签: spring grails spring-security