java 在 Spring 注解中使用静态变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17444856/
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
Using static variables in Spring annotations
提问by RobEarl
I'm using spring's PreAuthorize annotation as follows:
我正在使用 spring 的 PreAuthorize 注释如下:
@PreAuthorize("hasRole('role')");
However, I already have 'role' defined as a static String on another class. If I try to use this value:
但是,我已经将“角色”定义为另一个类上的静态字符串。如果我尝试使用此值:
@PreAuthorize("hasRole(OtherClass.ROLE)");
I get an error:
我收到一个错误:
org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 14): Field or property 'OtherClass' cannot be found on object of type 'org.springframework.security.access.expression.method.MethodSecurityExpressionRoot'
Is there a way to access static variables like this with a PreAuthorize annotation?
有没有办法使用 PreAuthorize 注释访问这样的静态变量?
回答by Kevin Bowersox
Try the following which uses Spring Expression Language to evaluate the type:
尝试以下使用 Spring 表达式语言来评估类型的方法:
@PreAuthorize("hasRole(T(fully.qualified.OtherClass).ROLE)");
Be sure to specify the fully qualified class name.
请务必指定完全限定的类名。
回答by Magnus Heino
To make it possible to write expressions without package names:
为了可以编写没有包名的表达式:
<sec:global-method-security>
<sec:expression-handler ref="methodSecurityExpressionHandler"/>
</sec:global-method-security>
<bean id="methodSecurityExpressionHandler" class="my.example.DefaultMethodSecurityExpressionHandler"/>
Then extend the DefaultMethodSecurityExpressionHandler:
然后扩展 DefaultMethodSecurityExpressionHandler:
public class DefaultMethodSecurityExpressionHandler extends org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler {
@Override
public StandardEvaluationContext createEvaluationContextInternal(final Authentication auth, final MethodInvocation mi) {
StandardEvaluationContext standardEvaluationContext = super.createEvaluationContextInternal(auth, mi);
((StandardTypeLocator) standardEvaluationContext.getTypeLocator()).registerImport("my.example");
return standardEvaluationContext;
}
}
Now create my.example.Roles.java :
现在创建 my.example.Roles.java :
public class Roles {
public static final String ROLE_UNAUTHENTICATED = "ROLE_UNAUTHENTICATED";
public static final String ROLE_AUTHENTICATED = "ROLE_AUTHENTICATED";
}
And refer to it without package name in annotations:
并在注释中没有包名的情况下引用它:
@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATED)")
instead of:
代替:
@PreAuthorize("hasRole(T(my.example.Roles).ROLE_AUTHENTICATED)")
Makes it more readable imho. Also roles are now typed. Write:
让它更具可读性恕我直言。现在也输入了角色。写:
@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATEDDDD)")
and you will get startup errors that wouldn't have been there if you wrote:
并且您将收到启动错误,如果您这样写,则不会出现这些错误:
@PreAuthorize("hasRole('ROLE_AUTHENTICATEDDDD')")
回答by Henry
The accepted answer from Kevin Bowersox works, but I didn't like having the T(fully.qualified.path) stuff so I kept looking. I started by creating a custom security method using the answer from James Watkins here:
Kevin Bowersox 接受的答案有效,但我不喜欢 T(fully.qualified.path) 的东西,所以我一直在寻找。我首先使用 James Watkins 的答案创建自定义安全方法:
How to create custom methods for use in spring security expression language annotations
However, instead of a String, I used my enums.Permissions class as the parameter type:
但是,我使用 enums.Permissions 类作为参数类型,而不是 String:
@Component
public class MySecurityService {
public boolean hasPermission(enums.Permissions permission) {
...do some work here...
return true;
}
}
Now the neat part is that when I call the hasPermission from an annotation, I don't have to have to type the whole path, but I do have to enclose it in single quotes:
现在简洁的部分是,当我从注释中调用 hasPermission 时,我不必输入整个路径,但我必须将它括在单引号中:
@PreAuthorize("@mySecurityService.hasPermission('SOME_ROLE_NAME')")
Because the hasPermission method expects an Enum, it will automatically find the Enum value with that name. If it doesn't find it you'll get an exception:
因为 hasPermission 方法需要一个 Enum,它会自动找到具有该名称的 Enum 值。如果它没有找到它,你会得到一个例外:
org.springframework.expression.spel.SpelEvaluationException: Type conversion problem, cannot convert from java.lang.String to enums.Permissions
You can rename hasPermission to hasRole, in which case the only trade off is that you are trading T(fully.qualified.path) for @mySecurityService and extra single quotes.
您可以将 hasPermission 重命名为 hasRole,在这种情况下,唯一的折衷是您将 T(fully.qualified.path) 交易为 @mySecurityService 和额外的单引号。
Not sure if it is any better, but there it is. Since none of this is going to verify the values at compile time anyways, my next step is to make an annotation processor.
不确定它是否更好,但它确实存在。由于无论如何这些都不会在编译时验证值,我的下一步是制作一个注释处理器。
I also have to give credit to krosenvold for pointing out that spring can automatically convert to an enum: https://stackoverflow.com/a/516899/618881
我还必须感谢 krosenvold 指出 spring 可以自动转换为枚举:https://stackoverflow.com/a/516899/618881
回答by Maksym Demidas
Try something like this:
尝试这样的事情:
@PreAuthorize("hasRole(T(com.company.enumpackage.OtherClass).ROLE.name())");
If your OtherClass enum is declared as public static, then you need to use $ sign:
如果您的 OtherClass 枚举被声明为 public static,那么您需要使用 $ 符号:
@PreAuthorize("hasRole(T(com.company.ParentTopLevelClass$OtherClass).ROLE.name())");
name()
to prevent futer problems if toString()
will be overriden later
name()
以防止以后出现问题,如果toString()
以后会被覆盖
回答by Алексей Виноградов
You can also create a bean container with roles, like:
您还可以创建具有角色的 bean 容器,例如:
@Component("R")
public final class RoleContainer {
public static final String ROLE_A = "ROLE_A";
}
then on controller you can use:
然后在控制器上你可以使用:
@PreAuthorize("hasRole(@R.ROLE_A)")