Spring Security taglib sec:authorize with role hierarchy not working

China☆狼群 提交于 2020-01-04 14:14:53

问题


I can't get sec:authorize hasRole() to work with the role hierarchy. If I have a user with role ROLE_BOSS which is the parent of ROLE_WORKER, then is false for some reason. In my service classes @PreAuthorize("hasRole('ROLE_WORKER')") does work however. I assumed they both used the same evaluator, so why doesn't the taglib work? Thanks for the help.

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 security:

<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>

回答1:


For someone like me working with Java Config. This is a very simple solution here to just add the following code in your class extending 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);
    }



回答2:


Very strange and I don't think this is correct, but it seems to work. I started digging through the Spring source code and I think I got it to work by taking the DefaultWebSecurityExpressionHandler out of the accessDecisionManager and placing it at the very top of all my security configurations. So at the top of my -config.xml I have this:

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

And my accessDecisionManager is now:

<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>



回答3:


Have you tried?

<%@ 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> 

or

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


来源:https://stackoverflow.com/questions/13132922/spring-security-taglib-secauthorize-with-role-hierarchy-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!