繁体   English   中英

如何创建用于 spring 安全表达式语言注释的自定义方法

[英]How to create custom methods for use in spring security expression language annotations

我想创建一个 class 添加自定义方法以用于 spring 安全表达式语言,以通过注释进行基于方法的授权。

例如,我想创建一个像“customMethodReturningBoolean”这样的自定义方法,以这样的方式使用:

  @PreAuthorize("customMethodReturningBoolean()")
  public void myMethodToSecure() { 
    // whatever
  }

我的问题是这个。 If it is possible, what class should I subclass to create my custom methods, how would I go about configuring it in the spring xml configuration files and come someone give me an example of a custom method used in this way?

上述技术均不再适用。 似乎 Spring 已经竭尽全力防止用户覆盖 SecurityExpressionRoot。

编辑 11/19/14 设置 Spring 以使用安全注释:

<beans ... xmlns:sec="http://www.springframework.org/schema/security" ... >
...
<sec:global-method-security pre-post-annotations="enabled" />

像这样创建一个bean:

@Component("mySecurityService")
public class MySecurityService {
    public boolean hasPermission(String key) {
        return true;
    }
}

然后在您的 jsp 中执行以下操作:

<sec:authorize access="@mySecurityService.hasPermission('special')">
    <input type="button" value="Special Button" />
</sec:authorize>

或者注释一个方法:

@PreAuthorize("@mySecurityService.hasPermission('special')")
public void doSpecialStuff() { ... }

此外,您可以在@PreAuthorize注释中使用Spring 表达式语言来访问当前身份验证以及方法 arguments。

例如:

@Component("mySecurityService")
public class MySecurityService {
    public boolean hasPermission(Authentication authentication, String foo) { ... }
}

然后更新您的@PreAuthorize以匹配新方法签名:

@PreAuthorize("@mySecurityService.hasPermission(authentication, #foo)")
public void doSpecialStuff(String foo) { ... }

您需要对两个类进行子类化。

首先,设置一个新的方法表达式处理程序

<global-method-security>
  <expression-handler ref="myMethodSecurityExpressionHandler"/>
</global-method-security>

myMethodSecurityExpressionHandler将是DefaultMethodSecurityExpressionHandler的子类,它覆盖createEvaluationContext() ,在MethodSecurityExpressionRoot上设置MethodSecurityEvaluationContext的子类。

例如:

@Override
public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
    MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer);
    MethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(auth);
    root.setTrustResolver(trustResolver);
    root.setPermissionEvaluator(permissionEvaluator);
    root.setRoleHierarchy(roleHierarchy);
    ctx.setRootObject(root);

    return ctx;
}

感谢ericacm ,但由于以下几个原因它不起作用:

  • DefaultMethodSecurityExpressionHandler的属性是私有的(反射可见性不受欢迎)
  • 至少在我的 Eclipse 中,我无法解析MethodSecurityEvaluationContext object

不同之处在于我们调用现有的createEvaluationContext方法,然后添加我们的自定义根 object。 最后我只返回了一个StandardEvaluationContext object 类型,因为 MethodSecurityEvaluationContext 不会在编译器中解析(它们都来自同一个接口)。 这是我现在在生产中的代码。

MethodSecurityExpressionHandler使用我们的自定义根:

public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler  {

    // parent constructor
    public CustomMethodSecurityExpressionHandler() {
        super();
    }

    /**
     * Custom override to use {@link CustomSecurityExpressionRoot}
     * 
     * Uses a {@link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt> implementation and
     * configures it with a {@link MethodSecurityExpressionRoot} instance as the expression root object.
     */
    @Override
    public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
        // due to private methods, call original method, then override it's root with ours
        StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi);
        ctx.setRootObject( new CustomSecurityExpressionRoot(auth) );
        return ctx;
    }
}

这通过扩展SecurityExpressionRoot替换了默认根。 在这里,我将 hasRole 重命名为 hasEntitlement:

public class CustomSecurityExpressionRoot extends SecurityExpressionRoot  {

    // parent constructor
    public CustomSecurityExpressionRoot(Authentication a) {
        super(a);
    }

    /**
     * Pass through to hasRole preserving Entitlement method naming convention
     * @param expression
     * @return boolean
     */
    public boolean hasEntitlement(String expression) {
        return hasRole(expression);
    }

}

最后更新 securityContext.xml (并确保它是从您的 applcationContext.xml 中引用的):

<!-- setup method level security using annotations -->
<security:global-method-security
        jsr250-annotations="disabled"
        secured-annotations="disabled"
        pre-post-annotations="enabled">
    <security:expression-handler ref="expressionHandler"/>
</security:global-method-security>

<!--<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">-->
<bean id="expressionHandler" class="com.yourSite.security.CustomMethodSecurityExpressionHandler" />

注意: @Secured 注解将不接受此覆盖,因为它通过不同的验证处理程序运行。 因此,在上面的 xml 中,我禁用了它们以防止以后混淆。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM