2013-07-03 61 views
10

我使用Spring的预授权注解如下静态变量:使用Spring注解

@PreAuthorize("hasRole('role')"); 

不过,我已经定义为另一个类的静态字符串“角色”。如果我尝试使用这个值:

@PreAuthorize("hasRole(OtherClass.ROLE)"); 

我得到一个错误:

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' 

有没有像这样访问静态变量与预授权注释的方法吗?

回答

16

尝试它使用Spring表达式语言来评价类型如下:

@PreAuthorize("hasRole(T(fully.qualified.OtherClass).ROLE)"); 

确保指定的完全限定类名。

Documentation

+0

伟大的作品,谢谢! – RobEarl

+0

@RobEarl真棒很高兴我能帮到你。我也学到了一些东西。 –

+0

Works,但它仍然是一个解释的字符串,所以当您重构例如Eclipse时,它不会被Eclipse“看到”。我猜的名字。 – yglodt

3

尝试是这样的:如果你的OtherClass枚举被声明为公共静态

@PreAuthorize("hasRole(T(com.company.enumpackage.OtherClass).ROLE.name())"); 

,那么你需要使用$符号:

@PreAuthorize("hasRole(T(com.company.ParentTopLevelClass$OtherClass).ROLE.name())"); 

name()防止futer问题如果toString()将在以后被覆盖

4

凯文鲍尔索克斯接受的答案的作品,但我不喜欢有T(fully.qualified.path)的东西,所以我一直在寻找。我开始通过创建使用从詹姆斯·沃特金斯这里的答案自定义的安全方法:

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

然而,而不是一个字符串,我用我的enums.Permissions类作为参数类型:

@Component 
public class MySecurityService { 
    public boolean hasPermission(enums.Permissions permission) { 

     ...do some work here... 

     return true; 
    } 
} 

现在整齐的部分是,当我打电话从注释调用hasPermission,我没有有键入完整的路径,但我必须把它们放在单引号:

@PreAuthorize("@mySecurityService.hasPermission('SOME_ROLE_NAME')") 

因为hasPermission方法需要Enum,它将自动查找具有该名称的Enum值。如果它没有找到它,你会得到一个例外:

org.springframework.expression.spel.SpelEvaluationException: Type conversion problem, cannot convert from java.lang.String to enums.Permissions 

可以重命名调用hasPermission到hasRole,在这种情况下唯一的代价就是你的交易T(fully.qualified.path) @mySecurityService和额外的单引号。

不知道它是否更好,但它是。由于无论如何都不会验证编译时的值,我的下一步是创建一个注释处理器。

我也必须给予信贷krosenvold您指出弹簧能自动转换为一个枚举: https://stackoverflow.com/a/516899/618881

6

为了能够写出表达式,而不包名:

<sec:global-method-security> 
    <sec:expression-handler ref="methodSecurityExpressionHandler"/> 
</sec:global-method-security> 

<bean id="methodSecurityExpressionHandler" class="my.example.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; 
    } 
} 

现在创建my.example.Roles.java:

public class Roles { 

    public static final String ROLE_UNAUTHENTICATED = "ROLE_UNAUTHENTICATED"; 

    public static final String ROLE_AUTHENTICATED = "ROLE_AUTHENTICATED"; 
} 

,并参考其不包名称注释:的

@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATED)") 

代替:

@PreAuthorize("hasRole(T(my.example.Roles).ROLE_AUTHENTICATED)") 

使它更具可读性恕我直言。现在还键入角色。写:

@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATEDDDD)") 

,你会得到一个不会在那里,如果你写的启动错误:

@PreAuthorize("hasRole('ROLE_AUTHENTICATEDDDD')") 
+0

好的解决方案。有启动错误会很好,但我不认为你可以实现这样的。评估仍然在运行时发生。还没有找到更好的解决方案,但很难... – chris