&引用;需要调试符号信息(…)”;注入修改后的Spring安全表达式语言实现

&引用;需要调试符号信息(…)”;注入修改后的Spring安全表达式语言实现,spring,grails,spring-security,Spring,Grails,Spring Security,我有一个示例类来测试@PreAuthorize注释,它看起来或多或少像这样: class BankService { @PreAuthorize("hasCustomRole('ROLE_CUSTOM') or hasRole('ROLE_EXAMPLE')") Double getAccountBalance(Integer accountNumber) { return 1234; } @PreAuthorize("#accountNumb

我有一个示例类来测试
@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(字符串表达式)
,我正在添加该注释:

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;
    }
}
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)
  }
}
最后,所有内容都包装在
资源中。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.
有趣的部分是
如果在表达式中使用参数名,则需要调试符号信息。
,这表明编译类时没有关于变量名的调试信息。但如果我不注射自己的豆子,一切都会很好

丢失调试信息的原因可能是什么?如何修复

它是一个Grails插件,为Grails2.0.4开发,使用1.2.7.3版的spring security核心插件、1.1版的spring security acl插件和3.0.7.0版的spring security

编辑:


为了使这个问题更有趣,我在后面发现了这样一个问题:如果您使用
javap
查看
.class
文件,“缺少”的调试信息实际上就在那里。因此类的编译是正确的,但Spring还是会抱怨…

我解决了这个问题,但是,我不确定为什么日志中的异常和消息与问题相去甚远

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

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

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

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;
    }
}
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)
  }
}
一切正常,测试通过