Spring security @secure 不适用于角色层次结构

Posted

技术标签:

【中文标题】Spring security @secure 不适用于角色层次结构【英文标题】:Spring security @secure not working with role hierarchy 【发布时间】:2013-10-31 05:24:29 【问题描述】:

我在 Spring Security 中使用角色层次结构,我的 spring-securityConfig.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
              http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
              http://www.springframework.org/schema/security 
              http://www.springframework.org/schema/security/spring-security-3.1.xsd">

     <bean id="roleHierarchy"  class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
        <property name="hierarchy">
            <value>
                ROLE_ADMIN > ROLE_WORKFLOW
                ROLE_ADMIN > ROLE_ISBN_INSERTION
                ROLE_ADMIN > ROLE_PERMISSION_UPDATE
                ROLE_ADMIN > ROLE_ASSIGNMENT
                ROLE_ADMIN > ROLE_CALIBRATION
            </value>
        </property>
    </bean>

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

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

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

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

     <bean id="authenticationEntryPoint"
          class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
        <property name="loginFormUrl" value="/login.htm" />
    </bean>





    <security:http entry-point-ref="authenticationEntryPoint" disable-url-rewriting="true" access-decision-manager-ref="accessDecisionManager">

        <security:session-management>
            <security:concurrency-control error-if-maximum-exceeded="true" max-sessions="1"/>
        </security:session-management>

        <security:custom-filter position="FORM_LOGIN_FILTER"
                                ref="cdlAuthenticationProcessingFilter" />


        <security:intercept-url pattern="/displayGroupRoleEditView.htm" access="ROLE_PERMISSION_UPDATE" />

        <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />

        <security:access-denied-handler ref="accessDeniedHandler" />

    </security:http>


    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="cdlLdapAuthenticationProvider"/> 
        <security:authentication-provider user-service-ref="cdlUserDetailService"/>
    </security:authentication-manager>


    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="cdlLdapAuthenticationProvider"/> 
        <security:authentication-provider user-service-ref="cdlUserDetailService"/>
    </security:authentication-manager>

    <bean name="commonPropertyBean" class="com.qait.cdl.commons.domain.CommonPropertyBean"
          abstract="true">
        <property name="userDao" ref="userDao"/>
    </bean> 

    <bean name="commonAuthoritiesPopulator" class="com.qait.cdl.authentication.customfilter.AuthoritiesPopulator" parent ="commonPropertyBean"  />

    <bean id="cdlLdapAuthenticationProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
        <constructor-arg ref="customLdapBindAuthenticator"/>
        <constructor-arg ref="cdlAuthoritiesPopulator"/>
    </bean>

    <bean id="customLdapBindAuthenticator" class="org.springframework.security.ldap.authentication.BindAuthenticator">
        <constructor-arg ref="cdlLdapContextSource" />
        <property name="userDnPatterns">
            <list>
                <value>$ldap.userDnPatterns</value>
            </list>
        </property>
    </bean>

    <bean id="cdlLdapContextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
        <constructor-arg value="$ldap.url"/>
    </bean>

    <bean id="cdlAuthoritiesPopulator" class="com.qait.cdl.authentication.customfilter.CdlUserAuthoritiesPopulator" parent="commonAuthoritiesPopulator"/>

    <bean id="cdlUserDetailService" class="com.qait.cdl.authentication.service.impl.UserDetailsServiceImpl" parent="commonAuthoritiesPopulator"/>

    <bean id="cdlAuthenticationProcessingFilter" class="com.qait.cdl.authentication.customfilter.CustomAuthenticationProcessingFilter" parent="commonPropertyBean">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="notificationService" ref="notificationService"/>
        <property name="userGroupDao" ref="userGroupDao"/>
    </bean>

    <bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
       <property name="errorPage" value="/cdlAccessDenied.htm" />
    </bean>

    <security:global-method-security secured-annotations="enabled"  pre-post-annotations="enabled" />
   <bean name="/cdlAccessDenied.htm" class="com.qait.cdl.authentication.web.CDLAccessDeniedHandler"/>
</beans>              

在服务方法中,如果用户使用了 @Secured( "ROLE_PERMISSION_UPDATE") 角色 ROLE_ADMIN 正在登录应用程序并尝试访问此安全方法,然后抛出拒绝访问异常。

【问题讨论】:

【参考方案1】:

我找到了解决办法

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

将此添加到dispatcher-servlet.xml。 spring security 应该有不同的上下文

添加

<context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>
         WEB-INF/applicationContext.xml
         WEB-INF/dispatcher-servlet.xml
     </param-value>
</context-param>

到您的 web.xml 并在 applicationContext.xml 中导入 spring-security.xml 这样做的唯一目的是为 spring 安全性提供单独的上下文。

要将基于方法的安全性应用于角色层次结构,请使用 @PreAuthorize("SpEL") 代替 @Secured()

【讨论】:

【参考方案2】:

您只为 DefaultWebSecurityExpressionHandler 启用了 roleHierarchy,它将适用于您的 http 请求,但不适用于 @Secured 注释。也将其添加到 DefaultMethodSecurityExpressionHandler

<global-method-security ...>
    <expression-handler ref = "methodSecurityExpressionHandler" />
</global-method-security>

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

【讨论】:

以上是关于Spring security @secure 不适用于角色层次结构的主要内容,如果未能解决你的问题,请参考以下文章

尽管我们不提供 Spring Security 配置,为啥 Spring Security 应用程序会重定向到登录页面?

Spring-security-cas 插件单点注销不起作用

Spring Security CORS 不工作

spring security 不支持application/json 解决办法

Spring Security问题

Spring security jsp授权标签不起作用