【问题标题】:Spring Security taglib sec:authorize with role hierarchy not workingSpring Security taglib sec:授权与角色层次结构不起作用
【发布时间】:2012-10-19 10:25:10
【问题描述】:

我无法让 sec:authorize hasRole() 使用角色层次结构。如果我有一个角色为 ROLE_BOSS 的用户,它是 ROLE_WORKER 的父级,那么由于某种原因是错误的。但是,在我的服务类中,@PreAuthorize("hasRole('ROLE_WORKER')") 确实有效。我假设他们都使用相同的评估器,那么为什么 taglib 不起作用?感谢您的帮助。

JSP:

<sec:authorize access="hasRole('ROLE_BOSS')">
  <p>This shows up.</p>
</sec:authorize>
<sec:authorize access="hasRole('ROLE_WORKER')">
  <p>This does not show up, but should.</p>
</sec:authorize>

-config.xml 安全性:

<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
  <property name="permissionEvaluator" ref="permissionEvaluator"/>
  <property name="roleHierarchy" ref="roleHierarchy"/>
</bean>

<sec:global-method-security pre-post-annotations="enabled">
  <sec:expression-handler ref="expressionHandler"/>
</sec:global-method-security>

<bean id="permissionEvaluator" class="com.myapp.security.MyPermissionEvaluator">
  <constructor-arg index="0">
    <map key-type="java.lang.String" value-type="com.myapp.security.Permission">
      <entry key="contractReadAccess" value-ref="contractReadPermission"/>
      <entry key="contractWriteAccess" value-ref="contractWritePermission"/>
    </map>
  </constructor-arg>
</bean>

<bean id="contractReadPermission" class="com.myapp.security.ContractReadPermission"/>
<bean id="contractWritePermission" class="com.myapp.security.ContractWritePermission"/>

<sec:http use-expressions="true" access-decision-manager-ref="accessDecisionManager">
  <sec:intercept-url pattern="/worker/**" access="isAuthenticated()" requires-channel="https"/>
  <sec:intercept-url pattern="/boss/**" access="hasRole('ROLE_BOSS')" requires-channel="https"/>

  <sec:form-login login-page="/login" authentication-failure-url="/login?login_error=1" authentication-success-handler-ref="successHandler"/>
  <sec:logout logout-url="/logout" logout-success-url="/login" invalidate-session="true"/>
<sec:remember-me/>
</sec:http>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
  <constructor-arg>
    <list>
      <ref bean="roleVoter" />
      <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>
  </constructor-arg>
</bean>

<bean id="roleVoter" 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_BOSS > ROLE_WORKER
    </value>
  </property>
</bean>

<sec:authentication-manager alias="authenticationManager">
  <sec:authentication-provider user-service-ref="myUserDetailsService"/>
</sec:authentication-manager>

【问题讨论】:

    标签: spring spring-security authorization roles taglib


    【解决方案1】:

    对于像我这样使用 Java Config 的人。这是一个非常简单的解决方案,只需在扩展 WebSecurityConfigurerAdapter 的类中添加以下代码:

    @Bean
        public RoleHierarchyVoter roleVoter() {
            return new RoleHierarchyVoter(roleHierarchy());
        }
    
        @Bean
        public RoleHierarchy roleHierarchy() {
            RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
            roleHierarchy.setHierarchy("ROLE_BOSS > ROLE_WORKER");
            return roleHierarchy;
        }
    
        private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
            DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
            defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
            return defaultWebSecurityExpressionHandler;
        }
    
        @Override
        public void init(WebSecurity web) throws Exception {
            web.expressionHandler(webExpressionHandler());
            super.init(web);
        }
    

    【讨论】:

    • 这为我解决了。也许这与缺少安全投票者有关,也许 Init 方法迫使它工作。
    【解决方案2】:

    你试过了吗?

    <%@ taglib prefix='sec' uri='http://www.springframework.org/security/tags' %> 
    
    <sec:authorize ifAnyGranted='ROLE_BOSS,ROLE_WORKER'> 
      <h1>ROLE_BOSS and ROLE_WORKER can see this</h1><br/> 
    </sec:authorize> 
    

    <sec:authorize access="hasAnyRole('ROLE_BOSS','ROLE_WORKER')">
      <h1>ROLE_BOSS and ROLE_WORKER can see this</h1><br/> 
    </sec:authorize> 
    

    【讨论】:

    • 当然可以,但是拥有角色层次结构背后的想法是我不必每次都定义我的所有角色。我只需要定义层次结构中最低的角色,每个人都继承自它。
    【解决方案3】:

    很奇怪,我认为这不正确,但它似乎有效。我开始深入研究 Spring 源代码,我认为我可以通过将 DefaultWebSecurityExpressionHandler 从 accessDecisionManager 中取出并将其放在我所有安全配置的最顶部来使其工作。所以在我的 -config.xml 顶部我有这个:

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

    我的 accessDecisionManager 现在是:

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

    【讨论】:

      猜你喜欢
      • 2018-06-03
      • 2014-09-13
      • 2013-10-23
      • 2023-02-24
      • 2016-01-03
      • 2012-12-01
      • 2013-10-31
      • 2016-02-28
      • 2019-06-21
      相关资源
      最近更新 更多