jakarta-ee - Spring Security - 'global-method-security' 不起作用

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

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

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

网页.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) {
    }

我在哪里做错了?

最佳答案

我解决了这个问题,所以我想在这里分享详细信息,以帮助其他人寻找 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>

这为我做了工作。

关于jakarta-ee - Spring Security - 'global-method-security' 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18663475/

相关文章:

java - Maven:远程运行单元测试

jakarta-ee - @Inject 初始化对象失败

spring-security - 为什么BCryptPasswordEncoder的强度在4到31之间?

java - 将属性文件或 xml 文件中的属性值注入(inject) PreAuthorize(...) java 注释(未解决)

java - 在 WebSphere 8.5 中覆盖 EJB 绑定(bind)名称

java - ASP.NET 没有像 Java EE 那样的标准对象池?

Spring Security - 基本 HTTP 身份验证 - 更改服务器消息

java - 如何使用 Spring Security ACL 获取用户有权访问的域对象列表?

php - 需要在单个资源 Controller 中使用 Entrust 角色的建议 - Laravel5

php - CodeIgniter 中的字段级 ACL