注入修改后的Spring安全表达式语言实现后,“需要调试符号信息(...)”

时间:2012-11-27 15:29:39

标签: spring grails spring-security

我有一个示例类来测试@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)注释中的@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 2.0.4开发的Grails插件,使用版本为1.2.7.3的spring-security-core插件,版本为1.1的spring-security-acl插件和Spring Security 3.0.7.RELEASE。

修改

为了使问题更有趣,这是我后来发现的:如果您使用.class查看javap文件,那么“缺少”的调试信息实际上就存在了。所以类是正确编译的,但是Spring总是抱怨......

1 个答案:

答案 0 :(得分:0)

我修复了这个问题,但是,我不确定为什么我所获得的日志中的异常和消息远离问题。

假设grails-app/conf/spring/resources.groovy的使用方式与使用Grails构建的应用程序类似,我犯了一个错误。虽然文档没有明确说明在resources.groovy中配置的bean在这种情况下不起作用,但它声明resources.groovy(在某些其他文件中)默认情况下将从打包中排除。

它没有解释运行测试时的奇怪行为,但它不是这种配置的好地方。

将Spring Security配置从resources.groovy移动到插件描述符后,按以下方式:

class MyOwnGrailsPlugin {

  /* ... some stuff ... */

  def doWithSpring = {
    /* ... some spring 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)
  }
}

一切正常,测试通过。