Spring Security Role Hierarchy not working with Thymeleaf sec:authorize

匿名 (未验证) 提交于 2019-12-03 00:56:02

问题:

I'm using Spring Security 3.2.5.RELEASE with ThymeLeaf 2.1.4.RELEASE. I've defined Role Hierarchy in my security context. In my view layer I'm using sec:authorize attribute to define menu items. I expect to see all menu items under the top level role but I only see the menus defined under that role. How can I fix this problem so that I see all menus under the top level?

Any pointers would be really appreciated. Thanks.

<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_ADMINISTRATOR > ROLE_MANAGER > ROLE_CONTENT_ADMINISTRATOR         </beans:value>     </beans:property> </beans:bean> 

And in my view page I'm using sec:authorize attribute like below:

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"       xmlns:th="http://www.thymeleaf.org"       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <body th:fragment="admin-menu" sec:authorize="hasRole('ROLE_ADMINISTRATOR')"> <li>     <a href="#"><i class="fa fa-users"></i> <span class="nav-label">Users</span> </a> </li> </body> </html> 

回答1:

In order to get the role hierarchy worked in thymeleaf templates as well as in the common security (annotation) config, you need only 2 things:

  1. Make the bean:

    @Bean public RoleHierarchyImpl roleHierarchy() { RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); String hierarchy =         "ADMIN_GLOBAL_MANAGEMENT > ADMIN_COMMON " +         "ADMIN_GLOBAL_MANAGEMENT > ADMIN_USER_MANAGEMENT " +         "ADMIN_GLOBAL_MANAGEMENT > ADMIN_PAYMENT_MANAGEMENT " +         "ADMIN_GLOBAL_MANAGEMENT > ADMIN_MESSAGE_MANAGEMENT";  roleHierarchy.setHierarchy(hierarchy);  return roleHierarchy; } 
  2. Extend WebSecurityConfigurerAdapter and override a method:

    @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {  ...  @Override public void configure(WebSecurity web) throws Exception {   DefaultWebSecurityExpressionHandler expressionHandler = new      DefaultWebSecurityExpressionHandler();   expressionHandler.setRoleHierarchy(roleHierarchy());   web.expressionHandler(expressionHandler); } 


回答2:

I had a similar problem with a similar hierarchy. The answer is explained here Spring Security Role Hierarchy issues. This works for me:

<sec:http> ...     <sec:expression-handler ref="defaultWebSecurityExpressionHandler" /> ... 

<beans:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">     <beans:property name="hierarchy">         <beans:value>             ROLE_SYSTEMADMIN > ROLE_JOURNALADMIN             ROLE_JOURNALADMIN > ROLE_ESUBS             ROLE_ESUBS > ROLE_STAFF         </beans:value>     </beans:property> </beans:bean>  <beans:bean id="methodSecurityExpressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">     <beans:property name = "roleHierarchy" ref="roleHierarchy"/> </beans:bean>  <beans:bean id="defaultWebSecurityExpressionHandler"       class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">       <beans:property name="roleHierarchy" ref="roleHierarchy"/> </beans:bean>    <beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">     <beans:constructor-arg>         <beans:list>             <beans:bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">                 <beans:constructor-arg ref="roleHierarchy" />             </beans:bean>             <beans:bean class="org.springframework.security.web.access.expression.WebExpressionVoter">                 <beans:property name="expressionHandler" ref="defaultWebSecurityExpressionHandler"/>             </beans:bean>         </beans:list>     </beans:constructor-arg> </beans:bean> 


回答3:

As a first instance I tried to update my dependencies, but with no luck.

Shortly what my application have: - web security configuration using role hierarchy - enabled global method security @EnableGlobalMethodSecurity(prePostEnabled = true)

All parts where working properly except Thymeleaf expression sec:authorize="hasRole('ROLE_USER')" did not take hierarchy into account.

Then I tried to debug, and I found out that when expression was evaluated, there were 2 DefaultWebSecurityExpressionHandler: - 1 with key webSecurityExpressionHandler - 1 with key defaultWebSecurityExpressionHandler (bean defined by me with hierarchy.

So I had 2 options: - either intercept webSecurityExpressionHandler an d sets role hierarchy on it; or - rename my bean definition from defaultWebSecurityExpressionHandler to webSecurityExpressionHandler.

As I don't need to have to security expression handler, I picked option number 2.

Note: In case you want to see if you don't have any other beans, see org.thymeleaf.extras.springsecurity4.auth.AuthUtils@243 (Line 243, method getExpressinHandler)

This might be the case in older version (inlcuding Thymeleaf 2.x.x)



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