Spring security 如何在Spring安全测试中通过SecurityContextFactory设置SecurityContext?
我使用的是Spring4.1.5和SpringSecurity4.0.0.RELEASE 我阅读了Rob Winch的文章,并开发了自己的WithSecurity ContextFactory实现,以便能够测试我的Spring MVC控制器:Spring security 如何在Spring安全测试中通过SecurityContextFactory设置SecurityContext?,spring-security,Spring Security,我使用的是Spring4.1.5和SpringSecurity4.0.0.RELEASE 我阅读了Rob Winch的文章,并开发了自己的WithSecurity ContextFactory实现,以便能够测试我的Spring MVC控制器: public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> { @Ov
public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> {
@Override
public SecurityContext createSecurityContext(WithMockCustomUser customUser) {
final User fakeUser = new User();
final SecurityUser principal = new SecurityUser(fakeUser);
final Authentication auth = new UsernamePasswordAuthenticationToken(principal, "password", HelpersTest.getAuthorities(customUser.faps()));
final SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(auth);
return context;
}
}
然后,我的具体测试类继承自AbstractResourceTest(从上面),并在启用@test的方法上使用以下注释:
@WithMockCustomUser(faps={"promotion_read"})
跟踪代码,我可以使用MockCustomUserSecurityContextFactory进行确认。调用createSecurityContext(),并在SecurityContextHolder.setContext()中设置其返回值(通过TestSecurityContextHolder.setContext())
到目前为止,一切都很好
但是,在该过程的稍后部分,SecurityContextPersistenceFilter.doFilter()调用SecurityContextHolder.setContext(),这将覆盖测试设置的上下文,我将无法跟踪我准备的模拟安全上下文
security.xml:
servlet.xml:
如何防止此安全上下文覆盖?我的security.xml是否包含我遗漏的明显缺陷
PS:我跳过了其他上下文配置文件,因为它们似乎与问题无关
提前谢谢 不幸的是,这篇博文只是为了方法级安全,没有关于MockMvc设置的完整说明(本系列中的以下博文有)。此外,这些博客实际上是过时的(我已经对它们进行了更新,以反映读者应该参考参考文档)。您可以在参考的中找到更新的说明 简而言之,将代码更新为以下内容:
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations =
{
"classpath:spring/mock-daos-and-scan-for-services.xml",
"classpath:security.xml",
"classpath:singletons.xml",
"classpath:controller-scan.xml",
"classpath:servlet.xml" })
public abstract class AbstractResourceMockMvcTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
[...]
@Before
public void setup() {
this.mockMvc =
MockMvcBuilders.webAppContextSetup(this.getWac())
.apply(springSecurity())
.build();
}
@Test
@WithMockCustomUser(faps={"promotion_read"})
public void myTest() {
...
}
[...]
}
一些亮点:
- 您不再需要提供TestExecutionListeners
- 使用.apply(springSecurity())而不是手动添加springSecurity筛选器链
apply(springSecurity())
将覆盖springSecurityFilterChain使用的SecurityContextRepository,以首先尝试TestSecurityContextHolder。springSecurity()帮助我获得了200,而我以前只有401
<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-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
"
>
<!-- HTTP security handling -->
<security:http use-expressions="true">
<security:logout logout-url="/j_spring_security_logout" invalidate-session="true" logout-success-url="/login.jsp?loggedout=true" />
<security:custom-filter before="FIRST" ref="multiTenantRequestFilter" />
<!-- make sure following page are not secured -->
<security:intercept-url pattern="/*/*/internal/**" access="hasIpAddress('127.0.0.1')" />
<!-- make sure everything else going through the security filter is secured -->
<security:intercept-url pattern="/resources/**" access="hasRole('ROLE_USER')" requires-channel="any" />
<!-- supporting basic authentication for unattended connections (web services) -->
<security:http-basic />
</security:http>
<!-- authentication strategy -->
<security:authentication-manager alias="authManager">
<security:authentication-provider user-service-ref="userSecurityService">
<security:password-encoder ref="passwordEncoder" />
</security:authentication-provider>
</security:authentication-manager>
<!-- custom filter to intercept the tenant name from the login form -->
<bean id="multiTenantRequestFilter" class="com.meicpg.ti.web.MultiTenantRequestFilter" />
</beans>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
"
>
<mvc:annotation-driven>
<!-- Content skipped for StackOverflow question -->
</mvc:annotation-driven>
<context:annotation-config />
<bean id="annotationExceptionResolver" class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
<security:global-method-security pre-post-annotations="enabled"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations =
{
"classpath:spring/mock-daos-and-scan-for-services.xml",
"classpath:security.xml",
"classpath:singletons.xml",
"classpath:controller-scan.xml",
"classpath:servlet.xml" })
public abstract class AbstractResourceMockMvcTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
[...]
@Before
public void setup() {
this.mockMvc =
MockMvcBuilders.webAppContextSetup(this.getWac())
.apply(springSecurity())
.build();
}
@Test
@WithMockCustomUser(faps={"promotion_read"})
public void myTest() {
...
}
[...]
}