如果使用 RoleHierarchyImpl,则 AccessDeniedException

Posted

技术标签:

【中文标题】如果使用 RoleHierarchyImpl,则 AccessDeniedException【英文标题】:AccessDeniedException if using RoleHierarchyImpl 【发布时间】:2011-12-10 04:38:24 【问题描述】:

我在 Spring Security 中使用角色层次结构。

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

<beans:bean id="roleHierarchy"
        class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <beans:property name="hierarchy">
        <beans:value>
            ROLE_USER > ROLE_GUEST
        </beans:value>
    </beans:property>
</beans:bean>

我正在使用保护切入点保护方法

<global-method-security secured-annotations="enabled" pre-post-annotations="enabled">
  <protect-pointcut expression="execution(* my.package.*(..))"
     access="ROLE_GUEST"/>
</global-method-security>

但是,如果我使用具有 ROLE_USER 权限的用户登录,则会收到 AccessDeniedException。如果我用access="ROLE_GUEST,ROLE_USER" 指定保护切入点,我没有问题。

我错过了一些步骤吗?仅供参考,我使用的是 Spring 3.0.5。

谢谢。

【问题讨论】:

【参考方案1】:

不要忘记添加一个 WebExpressionVoter 以便能够在 http 元素中使用表达式:

<sec:http use-expressions="true" access-decision-manager-ref="accessDecisionManager">
   <sec:intercept-url pattern="/index.html" access="hasRole('ROLE_AUTHENTICATED')" />
   <sec:intercept-url pattern="/admin" access="hasRole('ROLE_SUPERVISOR')" />
   ...

所以我最终得到了一个 accessDecisionManager,其中包含一个角色层次投票者和一个 WebExpressionVoter,两者都使用相同的 roleHierarchyImpl bean。

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
  <property name="decisionVoters">
    <list>
       <ref bean="roleHierarchyVoter" />
       <bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
           <property name="expressionHandler">
            <bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
               <property name="roleHierarchy" ref="roleHierarchy"/>
            </bean>
        </property>
       </bean>
       <bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
    </list>
  </property>
</bean>
<bean id="roleHierarchyVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
    <constructor-arg ref="roleHierarchy" />
</bean>

<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <property name="hierarchy">
        <value>
            ROLE_SUPERVISOR > ROLE_XX
            ROLE_XX > ROLE_AUTHENTICATED
            ROLE_AUTHENTICATED > ROLE_UNAUTHENTICATED
        </value>
    </property>
</bean>

(春季 3.1 节)

【讨论】:

【参考方案2】:

上面的 jgraglia 示例中的嵌套 bean 略有错误,您不需要 &lt;ref bean="roleHierarchyVoter" /&gt;,因为层次结构在 WebExpressionVoter 中处理。我在 Spring Security 4.0.0 中执行此操作,但代码看起来相同,只是您不需要 use-expressions="true",因为它默认处于启用状态。

我通常会尝试尽可能多地嵌套 bean,因此除非需要,否则我的代码没有 ref="" 值。

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
   <constructor-arg>
        <bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
            <property name="expressionHandler" ref="webExpressionHandler" />
        </bean>
   </constructor-arg>
</bean>

<bean id="webExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
    <property name="roleHierarchy" ref="roleHierarchy"/>
</bean>

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

【讨论】:

【参考方案3】:

查看错误报告SEC-1163 和下面的评论。

如果您需要对角色层次结构的基本支持,请使用 RoleHierarchyVoter,而不是 RoleVoter。

所以你需要这样的想法:

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
    <property name="decisionVoters">
        <list>              
            <ref bean="roleHierarchyVoter" />
            <ref bean="authenticatedVoter" />
            <ref bean="preAdviceVoter" />
            <ref bean="mediaItemReadVoter" />
            <ref bean="mediaItemWriteVoter" />
        </list>
    </property>
</bean>

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

【讨论】:

我看到,默认情况下,AffirmativeBased 实现用于 RoleVoter 和 AuthenticatedVoter。 static.springsource.org/spring-security/site/docs/3.0.x/…

以上是关于如果使用 RoleHierarchyImpl,则 AccessDeniedException的主要内容,如果未能解决你的问题,请参考以下文章

数据库:如果存在则“更新”如果不存在则插入 [重复]

Python使用pandas保存csv文件:如果文件存在则只添加内容(append),如果无表则同时写入表头和内容(write)

如果对象存在于全局中,则R从函数中从全局环境中获取对象,但如果不存在则使用不同的默认值

Postgres 如果不存在则插入多行,如果存在或插入则返回所有 id,然后使用所有 id 插入另一个表

SQL C++/CLi - 知道某物是不是在表中的方法,如果是,则使用它的 id,如果不是,则生成新的 id 并获取它

如果是浮点数则显示小数点 2 位,如果是整数则显示小数点数 0 位 [重复]