Java 如何创建用于 spring 安全表达式语言注释的自定义方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6632982/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create custom methods for use in spring security expression language annotations
提问by Paul D. Eden
I would like to create a class that adds custom methods for use in spring security expression language for method-based authorization via annotations.
我想创建一个类,该类添加自定义方法,用于通过注释进行基于方法的授权的 spring 安全表达式语言。
For example, I would like to create a custom method like 'customMethodReturningBoolean' to be used somehow like this:
例如,我想创建一个像“customMethodReturningBoolean”这样的自定义方法,以某种方式使用:
@PreAuthorize("customMethodReturningBoolean()")
public void myMethodToSecure() {
// whatever
}
My question is this. 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 xml 配置文件中配置它并且有人给我一个以这种方式使用的自定义方法的示例?
采纳答案by sourcedelica
You'll need to subclass two classes.
您需要对两个类进行子类化。
First, set a new method expression handler
首先,设置一个新的方法表达式处理程序
<global-method-security>
<expression-handler ref="myMethodSecurityExpressionHandler"/>
</global-method-security>
myMethodSecurityExpressionHandler
will be a subclass of DefaultMethodSecurityExpressionHandler
which overrides createEvaluationContext()
, setting a subclass of MethodSecurityExpressionRoot
on the MethodSecurityEvaluationContext
.
myMethodSecurityExpressionHandler
将是DefaultMethodSecurityExpressionHandler
其覆盖createEvaluationContext()
的子类,MethodSecurityExpressionRoot
在 上设置子类MethodSecurityEvaluationContext
。
For example:
例如:
@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;
}
回答by Joseph Lust
Thanks ericacm, but it does not work for a few reasons:
谢谢ericacm,但由于以下几个原因它不起作用:
- The properties of DefaultMethodSecurityExpressionHandlerare private (reflection visibility kludges undesirable)
- At least in my Eclipse, I can't resolve a MethodSecurityEvaluationContextobject
- DefaultMethodSecurityExpressionHandler的属性是私有的(反射可见性不受欢迎)
- 至少在我的 Eclipse 中,我无法解析MethodSecurityEvaluationContext对象
The differences are that we call the existing createEvaluationContextmethod and then add our custom root object. Finally I just returned an StandardEvaluationContextobject type since MethodSecurityEvaluationContext would not resolve in the compiler (they are both from the same interface). This is the code that I now have in production.
不同之处在于我们调用现有的createEvaluationContext方法,然后添加我们的自定义根对象。最后我只返回了一个StandardEvaluationContext对象类型,因为 MethodSecurityEvaluationContext 不会在编译器中解析(它们都来自同一个接口)。这是我现在在生产中的代码。
Make MethodSecurityExpressionHandleruse our custom root:
使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;
}
}
This replaces the default root by extending SecurityExpressionRoot. Here I've renamed hasRole to hasEntitlement:
这通过扩展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);
}
}
Finally update securityContext.xml (and make sure it's referenced from your applcationContext.xml):
最后更新 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" />
Note:the @Secured annotation will not accept this override as it runs through a different validation handler. So, in the above xml I disabled them to prevent later confusion.
注意:@Secured 注释不会接受此覆盖,因为它通过不同的验证处理程序运行。因此,在上面的 xml 中,我禁用了它们以防止以后混淆。
回答by James Watkins
None of the mentioned techniques will work anymore. It seems as though Spring has gone through great lengths to prevent users from overriding the SecurityExpressionRoot.
上面提到的技术都不会再起作用了。似乎 Spring 已经竭尽全力防止用户覆盖 SecurityExpressionRoot。
EDIT 11/19/14 Setup Spring to use security annotations:
编辑 11/19/14 设置 Spring 以使用安全注释:
<beans ... xmlns:sec="http://www.springframework.org/schema/security" ... >
...
<sec:global-method-security pre-post-annotations="enabled" />
Create a bean like this:
像这样创建一个bean:
@Component("mySecurityService")
public class MySecurityService {
public boolean hasPermission(String key) {
return true;
}
}
Then do something like this in your jsp:
然后在你的jsp中做这样的事情:
<sec:authorize access="@mySecurityService.hasPermission('special')">
<input type="button" value="Special Button" />
</sec:authorize>
Or annotate a method:
或者注释一个方法:
@PreAuthorize("@mySecurityService.hasPermission('special')")
public void doSpecialStuff() { ... }
Additionally, you may use Spring Expression Languagein your @PreAuthorize
annotations to access the current authentication as well as method arguments.
此外,您可以在注释中使用Spring 表达式语言@PreAuthorize
来访问当前的身份验证以及方法参数。
For example:
例如:
@Component("mySecurityService")
public class MySecurityService {
public boolean hasPermission(Authentication authentication, String foo) { ... }
}
Then update your @PreAuthorize
to match the new method signature:
然后更新您的@PreAuthorize
以匹配新的方法签名:
@PreAuthorize("@mySecurityService.hasPermission(authentication, #foo)")
public void doSpecialStuff(String foo) { ... }