如何创build用于Spring安全expression式语言注释的自定义方法

我想创build一个类,添加自定义方法,以便在Spring安全expression式语言中使用,以便通过注释进行基于方法的授权。

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

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

我的问题是这个。 如果可能的话,我应该inheritance哪个类来创build我的自定义方法,我将如何在spring xmlconfiguration文件中对其进行configuration,然后有人给我一个以这​​种方式使用的自定义方法的示例?

你需要inheritance两个类。

首先,设置一个新的方法expression式处理器

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

myMethodSecurityExpressionHandler将是DefaultMethodSecurityExpressionHandler一个子类,它重写createEvaluationContext() ,在MethodSecurityExpressionRoot上设置MethodSecurityExpressionRoot的子类。

例如:

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

没有提到的技术将工作了。 似乎Spring已经竭尽全力防止用户重写SecurityExpressionRoot。

编辑11/19/14安装Spring使用安全注解:

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

像这样创build一个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,并且必须通过扩展类,重写方法,实现接口等来解决问题,那么您可能做错了事情。 这是所有注释和XML,这就是为什么我们非常喜欢Spring,而不是(旧版本的)EJB。

另外,您可以在@PreAuthorize注解中使用Springexpression式语言来访问当前的authentication以及方法参数。

例如:

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

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

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

谢谢ericacm ,但它不起作用的几个原因:

  • DefaultMethodSecurityExpressionHandler的属性是私有的(reflection可见性kludges是不可取的)
  • 至less在我的Eclipse中,我无法parsingMethodSecurityEvaluationContext对象

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

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

这通过扩展SecurityExpressionRootreplace默认的根。 在这里,我把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注释不会接受这个覆盖,因为它通过一个不同的validation处理程序。 所以,在上面的XML我禁用他们,以防止以后的混淆。