为了账号安全,请及时绑定邮箱和手机立即绑定

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

/ 猿问

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

尚方宝剑之说 2019-09-19 14:30:16

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


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


  @PreAuthorize("customMethodReturningBoolean()")

  public void myMethodToSecure() { 

    // whatever

  }

我的问题是这个。如果有可能,我应该创建自定义方法的子类,我将如何在spring xml配置文件中配置它,有人给我一个这样使用的自定义方法的示例?


查看完整描述

3 回答

?
慕桂英3389331

您需要子类化两个类。


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


<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;

}


查看完整回答
反对 回复 2019-09-19
?
Cats萌萌

所提到的技术都不会再起作用了。看起来好像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() { ... }

此外,您可以在注释中使用Spring Expression Language@PreAuthorize来访问当前身份验证以及方法参数。


例如:


@Component("mySecurityService")

public class MySecurityService {

    public boolean hasPermission(Authentication authentication, String foo) { ... }

}

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


@PreAuthorize("@mySecurityService.hasPermission(authentication, #foo)")

public void doSpecialStuff(String foo) { ... }


查看完整回答
反对 回复 2019-09-19
?
繁华开满天机

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


DefaultMethodSecurityExpressionHandler的属性是私有的(反射可见性kludges不合需要)

至少在我的Eclipse中,我无法解析MethodSecurityEvaluationContext对象

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


Make MethodSecurityExpressionHandler使用我们的自定义root:


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中我禁用它们以防止以后出现混淆。


查看完整回答
反对 回复 2019-09-19

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信