我是Spring& amp;的新手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) {
}
我哪里弄错了?
答案 0 :(得分:6)
我解决了这个问题所以我想在这里分享一些细节,以帮助其他人搜索SS的全局安全功能可能无法正常工作的原因。
感谢Arten Bilan指出了正确的方向。我的问题的直接答案可能是:如果你想保护未定义为Spring Beans的代码,你应该使用“AspectJ auto-proxying”(mode =“aspectj”)。但是,你可能需要更多工作,就像我一样。
问题是,要启用aspectj,您应该使用 spring-security-aspects 模块中的 AnnotationSecurityAspect 编写代码,如所讨论的here。特别是Luke Taylor的帖子对我有帮助。
要实现这一点,您应该使用aspectj编译器编译代码。如果您现在正在使用 Maven ,则以下配置可能会有所帮助(如here所述):
首先使用modej方式设置:
<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>
这对我有用。
答案 1 :(得分:2)
看起来你应该遵循Spring Security Reference Manual中的recomendation:
仅对定义为Spring bean的实例(在启用了method-security的同一应用程序上下文中)保护带注释的方法。
此处讨论了类似的问题:How can <global-method-security> work on my controller by Spring-Security? 见最后一篇文章。