在使用 spring-session 的单元测试中,身份验证不应为空
Posted
技术标签:
【中文标题】在使用 spring-session 的单元测试中,身份验证不应为空【英文标题】:Authentication should not be null in unit tests with spring-session 【发布时间】:2018-06-19 17:15:07 【问题描述】:我有一个 spring boot(版本 1.5.9.RELEASE)应用程序,它使用 spring-session 在 Redis 上存储会话。它还使用 spring-security 对用户进行身份验证。运行应用程序时,成功登录后,安全上下文包含 Authentication 对象。但是在运行单元测试时,我收到此错误消息Authentication should not be null
。重现代码如下:
@SpringBootApplication
public class DemoRedisDataSessionApplication
@Configuration
@EnableWebSecurity
@EnableRedisHttpSession(redisNamespace = "demo-redis-spring-session")
public static class AppConfiguration extends WebSecurityConfigurerAdapter
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.inMemoryAuthentication().withUser("user").password("0000").roles("USER");
@Override
protected void configure(HttpSecurity http) throws Exception
http.formLogin().and()
.authorizeRequests().anyRequest().fullyAuthenticated();
@RestController
public static class AppController
@GetMapping("/secured")
public String secured()
return "secured";
public static void main(String[] args)
SpringApplication.run(DemoRedisDataSessionApplication.class, args);
这里是 application.properties
spring.session.store-type=redis
这是失败的测试
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class DemoRedisDataSessionApplicationTests
@Autowired
private MockMvc mockMvc;
@Test
public void testUserShouldBeAuthenticated() throws Exception
mockMvc.perform(formLogin().user("user").password("0000"))
.andExpect(status().is3xxRedirection())
.andExpect(authenticated());
失败测试的错误信息:
java.lang.AssertionError: Authentication should not be null
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:35)
at org.springframework.test.util.AssertionErrors.assertTrue(AssertionErrors.java:65)
at org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers$AuthenticatedMatcher.match(SecurityMockMvcResultMatchers.java:98)
尤其是 HttpSessionSecurityContextRepository
第 110 行中的会话似乎为空,但我不明白为什么。
我希望用户通过身份验证并在成功登录后填充SecurityContext
。你知道如何解决这个问题吗?
【问题讨论】:
【参考方案1】:更新:
首先,您需要指示您的身份验证提供程序(在您的情况下,它是默认的DaoAuthenticationProvider
)返回什么样的Authentication
对象。例如,您可以在自定义的WebSecurityConfigurerAdapter
中将httpBasic()
添加到您的configure(HttpSecurity http)
方法中。本质上,httpBasic() 会将您的用户名和密码转换为 UsernamePasswordAuthenticationToken 对象,以便您的 DaoAuthenticationProvider 可以使用它进行身份验证。
另外,你需要permitAll
为你的登录url。
@Override
protected void configure(HttpSecurity http) throws Exception
http.formLogin().and()
.authorizeRequests()
.antMatchers("/login/**").permitAll()
.anyRequest().fullyAuthenticated()
.and().httpBasic();
关于单元测试,问题是由于您没有将 spring 安全性连接到您的 mockMvc 对象中。由于您实际上是 spring-boot,我会给您一个带有 spring-boot-test 的示例解决方案:
@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
public class DemoRedisDataSessionApplicationTests
@Autowired
WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setUp()
mockMvc = MockMvcBuilders.webAppContextSetup(wac)
.apply(springSecurity())
.build();
@Test
public void testUserShouldBeAuthenticated() throws Exception
mockMvc.perform(formLogin().user("user").password("0000"))
.andExpect(status().is3xxRedirection())
.andExpect(authenticated());
重点说明:以上代码中的springSecurity()
来自import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity
。
【讨论】:
谢谢,但不幸的是,即使使用您提出的解决方案,我也会遇到同样的错误...我认为问题在于spring-session
库与单元测试的集成效果不佳。
不应该与 spring-session 相关的这个特定错误...您可以尝试在 AppConfiguration 的 protected void configure(HttpSecurity http) throws Exception
方法中添加 httpBasic()
吗?
法比奥,我的意思是:@Override protected void configure(HttpSecurity http) throws Exception http.formLogin().and() .authorizeRequests().anyRequest().fullyAuthenticated().and().httpBasic();
使用httpBasic()
可以正常使用,但不幸的是我们不能使用它...我们需要坚持使用formLogin()
法比奥,这两个概念并不冲突。 formLogin()
是为您的应用程序提供一个隐式登录页面,而httpBasic()
是为您的身份验证提供者提供一种对用户进行身份验证的方法。从本质上讲,httpBasic()
会将您的用户名和密码转换为 UsernamePasswordAuthenticationToken
对象,以便您的 DaoAuthenticationProvider
可以使用它进行身份验证。以上是关于在使用 spring-session 的单元测试中,身份验证不应为空的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 JDBC 在 spring-session 中初始化模式