【问题标题】:How to create typesafe user roles for Spring Security?如何为 Spring Security 创建类型安全的用户角色?
【发布时间】:2014-07-01 01:25:03
【问题描述】:

我想将spring-securityROLE_ADMINROLE_USER 角色一起使用。

因此我尝试创建一个类型安全的枚举类,但 @Secured 注释需要一个常量 String,而我无法通过使用枚举类来实现。

我可以在以下代码中进行哪些更改?

public enum UserRole {
    ADMIN("ROLE_ADMIN");

    private String role;

    public UserRole(String role) {  
        this.role = role;
    }
}

//error: The value for annotation attribute Secured.value must be a constant expression
@Secured(USerRole.ADMIN.value())
public class SecuredView {

}

【问题讨论】:

标签: java spring-security enums


【解决方案1】:

这个问题有点老了,但这是我的看法:

public enum Role implements GrantedAuthority {
    ROLE_USER, ROLE_ADMIN;

    @Override
    public String getAuthority() {
        return name();
    }
}

然后您可以将它与 @PreAuthorize 和 Spring Expression Language 一起使用来授权您的方法和类,如下所示:

@PreAuthorize("hasRole(T(<package name>.Role).ROLE_ADMIN)")
public void doSomeThing() {
    ...
}

注意:包名必须是完整的包名(org.company.project),并且不带。

如您所见,根据定义,这不是类型安全的,因为 SpEL 表达式仍然是字符串,但 IntelliJ 等 IDE 可以识别它们,并且会通知您任何错误。

您可以使用 hasAnyRole() 将 @PreAuthorize 与多个角色一起使用。

当然,对于许多角色,这可能会变得有点冗长,但您可以通过创建自己的注释来使其更漂亮,如下所示:

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@PreAuthorize("hasRole(T(<package name>.Role).ROLE_ADMIN)")
public @interface AdminAuthorization {
}

之后,您可以像这样授权您的方法:

@AdminAuthorization
public void doSomething() {
    ...
}

【讨论】:

  • 我想问一个关于答案的问题。我在答案中使用了解决方案。我想问什么;如何在层次结构中应用枚举类型。例如,ROLE_ADMIN> ROLE_USER
  • @forguta 这不是很漂亮,但你可以用@PreAuthorize("hasAnyRole(T(&lt;package name&gt;.Role).ROLE_ADMIN, T(&lt;package name&gt;.Role).ROLE_USER)") 注释你的@AdminAuthorization 注释
【解决方案2】:

部分解决方案:

public enum Role implements GrantedAuthority {

    ADMIN(Code.ADMIN),
    USER(Code.USER);

    private final String authority;

    Role(String authority) {
        this.authority = authority;
    }

    @Override
    public String getAuthority() {
        return authority;
    }

    public class Code {
        public static final String ADMIN = "ROLE_ADMIN";
        public static final String USER = "ROLE_USER";
    }
}

结果:

@Secured(Role.Code.ADMIN)

【讨论】:

  • IMO,这绝对是最“类型安全”的解决方案,因为其他提议的选项传递了“hasRole('MY_ROLE')”字符串,我几乎不会认为它是类型安全的。跨度>
【解决方案3】:

如果您使用的是 Lombok,则可以使用 @FieldNameConstants 注释:

@FieldNameConstants
public class UserRoles {
    private String ROLE_USER, ROLE_ADMIN;
}

然后像这样使用它:

@Secured(UserRoles.Fields.ROLE_ADMIN)

也许以后会有@EnumNameConstants注解,会更合适。

【讨论】:

    猜你喜欢
    • 2011-07-01
    • 2016-10-03
    • 2016-06-08
    • 2015-04-13
    • 2015-06-13
    • 1970-01-01
    • 2011-07-21
    • 2014-10-11
    • 2012-04-08
    相关资源
    最近更新 更多