【问题标题】:Spring Security - 'global-method-security' does not workSpring Security - “全局方法安全”不起作用
【发布时间】:2013-09-06 17:38:15
【问题描述】:

我是 Spring 和 Spring Security Frameworks 的新手,并尝试使用 Spring Security v3.1.4 保护在最新稳定 Glassfish 构建上运行的 Java EE 7 REST 应用程序。

一切都很好,但我无法让“全局方法安全”工作!这是我的配置,任何帮助将不胜感激。

web.xml:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/spring/*.xml
    </param-value>
</context-param>

<filter>
    <filter-name>filterChainProxy</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>filterChainProxy</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>    

Spring 应用程序上下文配置为预身份验证,如下所示:

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
        <property name="alwaysUseJndiLookup" value="true" />
    </bean>

    <bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
        <sec:filter-chain-map request-matcher="ant">
            <sec:filter-chain pattern="/api/authentication" filters="none"/>
            <sec:filter-chain pattern="/**" filters="sif,requestHeaderAuthFilder,logoutFilter,etf,fsi"/>
        </sec:filter-chain-map>
    </bean>

    <bean id="sif" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>

    <sec:authentication-manager alias="authenticationManager">
        <sec:authentication-provider ref='preAuthenticatedAuthenticationProvider'/>
    </sec:authentication-manager>

    <bean id="preAuthenticatedAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <property name="preAuthenticatedUserDetailsService">
            <bean id="userDetailsServiceWrapper"
                  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <property name="userDetailsService" ref="preAuthenticatedUserDetailsService"/>
            </bean>         
        </property>
    </bean>

    <bean id="preAuthenticatedUserDetailsService"
          class="org.someUserDetailsService"/>

    <bean id="requestHeaderAuthFilder" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="principalRequestHeader" value="sometoken"/>      
    </bean>

    <bean id="preAuthenticatedProcessingFilterEntryPoint"
          class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>

    <bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <constructor-arg value="/"/>
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
            </list>
        </constructor-arg>
    </bean>

    <bean id="servletContext" class="org.springframework.web.context.support.ServletContextFactoryBean"/>

    <bean id="etf" class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint" ref="preAuthenticatedProcessingFilterEntryPoint"/>
    </bean>

    <bean id="httpRequestAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions" value="false"/>
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter"/>
                <ref bean="authenticatedVoter"/>
            </list>
        </property>
    </bean>

    <bean id="fsi" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>      
        <property name="securityMetadataSource">
            <sec:filter-security-metadata-source use-expressions="true">
                <!--<sec:intercept-url  pattern="/api/authentication" access="permitAll"/>-->
                <sec:intercept-url pattern="/**" access="isAuthenticated()"/>
            </sec:filter-security-metadata-source>
        </property>

    </bean>

    <bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/>
    <bean id="authenticatedVoter" class="org.springframework.security.web.access.expression.WebExpressionVoter"/>

    <bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"/>  

以下是 Spring ACL 配置:

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


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

    <bean name="aclPermissionEvaluator"
          class="org.CustomPermissionEvaluator">
        <constructor-arg name="aclService" ref="aclService" />
        <property name="sidRetrievalStrategy" ref="someSidRetrievalStrategy" />
    </bean>   

    <bean id="lookupStrategy"
          class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
        <constructor-arg name="dataSource" ref="dataSource" />
        <constructor-arg name="aclCache" ref="aclCache" />
        <constructor-arg name="aclAuthorizationStrategy" ref="aclAuthorizationStrategy" />
        <constructor-arg name="auditLogger" ref="auditLogger" />
    </bean>

     <bean id="aclCache"
          class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
        <constructor-arg>
            <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
                <property name="cacheManager">
                    <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
                </property>
                <property name="cacheName" value="aclCache" />
            </bean>
        </constructor-arg>
    </bean>

    <bean id="aclAuthorizationStrategy"
          class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
        <constructor-arg name="auths">
            <list>
                <!-- authority for taking ownership -->
                <bean
                    class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                    <constructor-arg value="ROLE_ADMIN" />
                </bean>
                <!-- authority to modify auditing -->
                <bean
                    class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                    <constructor-arg value="ROLE_ADMIN" />
                </bean>
                <!-- authority to make general changes -->
                <bean
                    class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                    <constructor-arg value="ROLE_ADMIN" />
                </bean>
            </list>
        </constructor-arg>
        <property name="sidRetrievalStrategy" ref="someSidRetrievalStrategy"/>
    </bean>

    <bean id="someSidRetrievalStrategy" class="org.SomeSidRetrievalStrategyImpl"/>

    <bean id="auditLogger"
          class="org.springframework.security.acls.domain.ConsoleAuditLogger" />


    <jee:jndi-lookup 
        id="dataSource" 
        jndi-name="springacl" /> 


    <bean id="aclService" name="aclService"
          class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
        <constructor-arg name="dataSource" ref="dataSource" />
        <constructor-arg name="lookupStrategy" ref="lookupStrategy" />
        <constructor-arg name="aclCache" ref="aclCache" />
        <property name="sidIdentityQuery" value="select currval(pg_get_serial_sequence('acl_sid', 'id'))" />
        <property name="classIdentityQuery" value="select currval(pg_get_serial_sequence('acl_class', 'id'))" />
    </bean>

我要应用权限检查的方法如下:

    @GET
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    @PreAuthorize("hasPermission(#id, 'read')")
    public Project getProject(@PathParam("id") Long id) {
    }


我在哪里做错了?

【问题讨论】:

    标签: jakarta-ee spring-security acl spring-integration


    【解决方案1】:

    我解决了这个问题,所以我想在这里分享详细信息,以帮助其他人寻找 SS 的全局安全功能可能无法正常工作的原因。

    感谢Arten Bilan 为我指明了正确的方向。我的问题的直接答案可能是:如果您想保护未定义为 Spring Beans 的代码,您应该使用“AspectJ 自动代理”(mode="aspectj")。但是,您可能需要更多才能让它发挥作用,就像我所做的那样。

    问题是,要启用 aspectj,您应该使用 spring-security-aspects 模块中的 AnnotationSecurityAspect 编织代码,如 here 中讨论的那样。特别是Luke Taylor 的帖子对我很有帮助。

    要做到这一点,您应该使用 aspectj 编译器编译您的代码。如果您像我现在一样使用 Maven,以下配置可能会有所帮助(如 here 所讨论的):

    首先使用模式aspectj设置:

        <sec:global-method-security             
            pre-post-annotations="enabled"
            mode="aspectj"
            proxy-target-class="true">
            <sec:expression-handler ref="expressionHandler" />
        </sec:global-method-security>
    

    为 spring-security-aspects 模块添加依赖:

            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-aspects</artifactId>
                <version>3.1.4.RELEASE</version>
            </dependency>
    

    最后添加以下 maven 插件和配置以进行编译时编织:

            <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.4</version>
                    <configuration>
                        <showWeaveInfo>true</showWeaveInfo>
                        <source>1.7</source>
                        <target>1.7</target>
                        <Xlint>ignore</Xlint>
                        <complianceLevel>1.7</complianceLevel>
                        <encoding>UTF-8</encoding>
                        <verbose>false</verbose>
                        <aspectLibraries>
                            <aspectLibrary>
                                <groupId>org.springframework.security</groupId>
                                <artifactId>spring-security-aspects</artifactId>
                            </aspectLibrary>
                        </aspectLibraries>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                    <dependencies>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjrt</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjtools</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>
    

    这对我有用。

    【讨论】:

      【解决方案2】:

      看来您应该遵循 Spring Security 参考手册中的建议:

      只有定义为 Spring bean 的实例(在启用方法安全的同一应用程序上下文中)才会保护带注释的方法。

      这里讨论了一个类似的问题:How can <global-method-security> work on my controller by Spring-Security? 见上一篇。

      【讨论】:

      • 只提供链接作为答案不是一个好方法。如果以后更新或删除链接,您的回答将自动失效。最好能给出一些解释,然后给出链接作为参考。
      • 感谢您的回答 Artem。如果实例应该是能够使用方法安全注释的 Spring bean,那是否意味着我不能在 J2EE Web 应用程序中使用它?或者是否可以使用“AspectJ 自动代理”(mode="aspectj")?怎么样?
      • 好吧。再次来自 SS 文档:B.3.1 此元素是在 Spring Security bean 上添加对安全方法的支持的主要手段。可以通过使用注释(在接口或类级别定义)或通过使用 AspectJ 语法将一组切入点定义为子元素来保护方法。
      • 这里,请:Luke Taylor's explanation。样品在这里:GitHub
      猜你喜欢
      • 2021-12-15
      • 2012-10-27
      • 2012-01-01
      • 1970-01-01
      • 2015-09-20
      • 2019-09-13
      • 1970-01-01
      • 2011-10-04
      • 1970-01-01
      相关资源
      最近更新 更多