如何为 Spring Security 创建类型安全的用户角色?

Posted

技术标签:

【中文标题】如何为 Spring Security 创建类型安全的用户角色?【英文标题】:How to create typesafe user roles for 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 


【问题讨论】:

为什么不创建一个字符串类型的常量? 也许也看到这个答案:***.com/questions/19303584/… 【参考方案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注解,会更合适。

【讨论】:

以上是关于如何为 Spring Security 创建类型安全的用户角色?的主要内容,如果未能解决你的问题,请参考以下文章

如何为具有 Spring Security 配置的 Spring Boot API 编写单元测试

如何为 Spring Security 启用日志记录?

如何为 Spring Security 启用日志记录?

如何为登录GRAILS(Spring security)的用户实现会话?

如何为密钥持有者配置文件配置 Spring Security SAML 扩展

如何为 Webflux、Spring-Security、okta-spring-boot-starter 和 Okta-React 正确使用 CORS?