在Spring注释中使用静态变量

Rob*_*arl 16 java spring spring-security spring-annotations

我正在使用spring的PreAuthorize注释如下:

@PreAuthorize("hasRole('role')");
Run Code Online (Sandbox Code Playgroud)

但是,我已经将'role'定义为另一个类上的静态String.如果我尝试使用此值:

@PreAuthorize("hasRole(OtherClass.ROLE)");
Run Code Online (Sandbox Code Playgroud)

我收到一个错误:

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'
Run Code Online (Sandbox Code Playgroud)

有没有办法使用PreAuthorize注释访问这样的静态变量?

Kev*_*sox 26

尝试以下使用Spring Expression Language来评估类型:

@PreAuthorize("hasRole(T(fully.qualified.OtherClass).ROLE)");
Run Code Online (Sandbox Code Playgroud)

请务必指定完全限定的类名.

文档


小智 7

为了能够编写没有包名称的表达式:

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

<bean id="methodSecurityExpressionHandler" class="my.example.DefaultMethodSecurityExpressionHandler"/>
Run Code Online (Sandbox Code Playgroud)

然后扩展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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public class Roles {

    public static final String ROLE_UNAUTHENTICATED = "ROLE_UNAUTHENTICATED";

    public static final String ROLE_AUTHENTICATED = "ROLE_AUTHENTICATED";
}
Run Code Online (Sandbox Code Playgroud)

并在注释中没有包名称引用它:

@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATED)")
Run Code Online (Sandbox Code Playgroud)

代替:

@PreAuthorize("hasRole(T(my.example.Roles).ROLE_AUTHENTICATED)")
Run Code Online (Sandbox Code Playgroud)

使它更具可读性imho.此外,角色现在也是键入的.写:

@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATEDDDD)")
Run Code Online (Sandbox Code Playgroud)

如果你写的话,你会得到那些本不存在的启动错误:

    @PreAuthorize("hasRole('ROLE_AUTHENTICATEDDDD')")
Run Code Online (Sandbox Code Playgroud)


小智 6

您还可以创建具有角色的 bean 容器,例如:

@Component("R")
public final class RoleContainer {
  public static final String ROLE_A = "ROLE_A";
}
Run Code Online (Sandbox Code Playgroud)

然后在控制器上你可以使用:

@PreAuthorize("hasRole(@R.ROLE_A)")
Run Code Online (Sandbox Code Playgroud)

  • 最短、最简洁的答案! (2认同)

Mak*_*das 5

尝试这样的事情:

@PreAuthorize("hasRole(T(com.company.enumpackage.OtherClass).ROLE.name())");
Run Code Online (Sandbox Code Playgroud)

如果您的 OtherClass 枚举被声明为 public static,那么您需要使用 $ 符号:

@PreAuthorize("hasRole(T(com.company.ParentTopLevelClass$OtherClass).ROLE.name())");
Run Code Online (Sandbox Code Playgroud)

name()防止以后出现问题 iftoString()稍后会被覆盖


Hen*_*nry 5

Kevin Bowersox 接受的答案有效,但我不喜欢 T(fully.qualified.path) 的东西,所以我一直在寻找。我首先使用 James Watkins 的答案创建自定义安全方法:

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

但是,我使用 enums.Permissions 类作为参数类型,而不是 String:

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

        ...do some work here...

        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在简洁的部分是,当我从注释中调用 hasPermission 时,我不必输入整个路径,但我必须将它括在单引号中:

@PreAuthorize("@mySecurityService.hasPermission('SOME_ROLE_NAME')")
Run Code Online (Sandbox Code Playgroud)

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

org.springframework.expression.spel.SpelEvaluationException: Type conversion problem, cannot convert from java.lang.String to enums.Permissions
Run Code Online (Sandbox Code Playgroud)

您可以将 hasPermission 重命名为 hasRole,在这种情况下,唯一的折衷是您将 T(fully.qualified.path) 交易为 @mySecurityService 和额外的单引号。

不确定它是否更好,但它确实存在。由于无论如何这些都不会在编译时验证值,我的下一步是制作一个注释处理器。

我还必须感谢 krosenvold 指出 spring 可以自动转换为枚举:https ://stackoverflow.com/a/516899/618881