在 Spring Security 中实现分层角色

Posted

技术标签:

【中文标题】在 Spring Security 中实现分层角色【英文标题】:Implementing Hierarchical Roles in Spring Security 【发布时间】:2014-05-01 21:44:16 【问题描述】:

我正在尝试在 Spring 安全性中实现分层角色,并根据 spring 源文档在我的 xml 文件中添加以下配置。

<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <property name="hierarchy">
        <value>
            ROLE_ADMIN > ROLE_PRO
            ROLE_PRO > ROLE_PREMIUM
            ROLE_PREMIUM > ROLE_BASIC
            ROLE_BASIC > ROLE_ANONYMOUS
        </value>
    </property>
</bean>

 <bean id="roleVoter"
        class="org.springframework.security.access.vote.RoleHierarchyVoter">
         <constructor-arg ref="roleHierarchy"/>
</bean>

我已经尝试过以上几行,但是当 ROLE_ADMIN 尝试访问分配给 ROLE_BASIC 的 url 时,我得到了拒绝访问。除了这个,我还需要添加什么吗?除了 Spring 站点中的那些行,我什么也没找到。另外,如果您知道分层角色的任何良好实现,请务必提及。

【问题讨论】:

【参考方案1】:

我认为您需要在accessDecisionManager 注册roleVoter。 @参见this answer 示例。


但老实说,我doubt the Spring Hierarchical Voter concept,因为你需要在任何地方添加一个特殊的分层投票者。我个人更喜欢另一种方式:我实现了一个自定义JdbcDaoImpl,它覆盖了addCustomAuthorities,并将“普通”角色添加到“现有”角色一次。

/**
 * Extension of @link JdbcDaoImpl User Detail Provider, so that is uses the
 * @link PrivilegesService to extend the provided Authorities.
 *
 */
public class JdbcDaoPrivilegesImpl extends JdbcDaoImpl 

    private PrivilegesService privilegesService;

    public JdbcDaoPrivilegesImpl(final PrivilegesService privilegesService)         
        this.privilegesService = privilegesService;
    

    @Override
    protected void addCustomAuthorities(String username, List<GrantedAuthority> authorities) 
        super.addCustomAuthorities(username, authorities);         

        List<GrantedAuthority> privileges = new ArrayList<GrantedAuthority>();
        for (GrantedAuthority role : authorities) 
            privileges.addAll(privilegesService.getPrivilegesForRole(role));
        
        authorities.addAll(privileges);    
    



public interface PrivilegesService 

     Collection<? extends GrantedAuthority> getPrivilegesForRole(GrantedAuthority role);



public class PropertyPrivilegesServiceImpl implements PrivilegesService 

    /**
     * Property bases mapping of roles to privileges.
     * Every role is one line, the privileges are comma separated.
     */
    private Properties roleToPrivileges;

    public PropertyPrivilegesServiceImpl(Properties roleToPrivileges) 
        if (roleToPrivileges == null) 
            throw new IllegalArgumentException("roleToPrivileges must not be null");
        
        this.roleToPrivileges = roleToPrivileges;
    

    @Override
    public Collection<? extends GrantedAuthority> getPrivilegesForRole(GrantedAuthority role) 
        if (roleToPrivileges == null) 
            throw new IllegalArgumentException("role must not be null");
        

        String authority = role.getAuthority();
        if(authority != null) 
            String commaSeparatedPrivileges = roleToPrivileges.getProperty(role.getAuthority());
            if (commaSeparatedPrivileges != null) 
                List<GrantedAuthority> privileges = new ArrayList<GrantedAuthority>();
                for(String privilegeName : StringUtils.commaDelimitedListToSet(commaSeparatedPrivileges)) 
                    privileges.add(new GrantedAuthorityImpl(privilegeName.trim()));
                                
                return privileges;
             else 
                return Collections.emptyList();
            
         else 
            return Collections.emptyList();
        
    

示例配置

  <bean id="myUserDetailsService" class="JdbcDaoForUpdatableUsernames">
    <constructor-arg ref="propertyPrivilegesService"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="usersByUsernameQuery" value="SELECT login,encryptedPassword,loginEnabled FROM user WHERE login = ?"/>
    <property name="enableAuthorities" value="true"/>
    <property name="authoritiesByUsernameQuery" value="SELECT u.login, r.securityRoles FROM user u, user2security_roles r WHERE u.login= ? AND u.id = r. User_fk;"/>
</bean>

 <bean id="propertyPrivilegesService" class="PropertyPrivilegesServiceImpl">
    <constructor-arg>
        <props>
            <prop key="ROLE_ADMIN">
                ROLE_PREMIUM,
                ROLE_BASIC
            </prop>
            <prop key="ROLE_PREMIUM">
                RROLE_BASIC
            </prop>
        </props>
    </constructor-arg>
</bean>

【讨论】:

@carlspring:没有可用的公开示例。 (所有你需要在这个答案中实现这一点)。 -- 名称:我将其命名为“Role-Privilege-Approach”,但这不是正式名称。【参考方案2】:

尝试将其添加到 spring-security.xml

<http auto-config="true" use-expressions="true" access-decision-manager-ref="accessDecisionManager">


<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
    <beans:constructor-arg>
        <beans:list>
            <beans:ref bean="roleVoter" />
        </beans:list>
    </beans:constructor-arg>
</beans:bean>

【讨论】:

以上是关于在 Spring Security 中实现分层角色的主要内容,如果未能解决你的问题,请参考以下文章

如何在spring-security中切换角色

Spring Security 基于角色的授权问题

如何在 Spring Security 中实现基于 JWT 的身份验证和授权

在 Spring Security 2.06 中实现自定义 AuthenticationProvider

如何使用 spring-security-core-ldap 插件在 grails 中实现 LDAP 身份验证?

如何在 Spring Boot 中实现基于角色权限的系统