【问题标题】:Spring Security @WithMockUser doesn't seem to work with state changing verbs (post, put..)Spring Security @WithMockUser 似乎不适用于状态改变动词(post,put..)
【发布时间】:2019-11-10 02:37:49
【问题描述】:

这是我的设置:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/signup", "/health").permitAll()
            .anyRequest().authenticated().and()
        .formLogin()
            .loginPage("/login")
            .permitAll()
...

测试类:

@ExtendWith(SpringExtension.class)
@WebMvcTest
@WithMockUser
class ApiControllerTest {
    ...

@WithMockUser 可以正常使用以下 GET:

mockMvc.perform(get("/api/book/{id}", id))
        .andExpect(status().isOk())
...

但不使用 POST:

mockMvc.perform(post("/api/book")
        .contentType(MediaType.APPLICATION_JSON)
        .content(payload))
        .andExpect(status().isCreated())
...

当我查看 MockHttpServletResponse 的日志时,我注意到响应正在重定向到登录页面,如下所示:

MockHttpServletResponse:
           Status = 302
    Error message = null
          Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY", Location:"/login"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = /login
          Cookies = []

我知道@WithMockUser 为模拟用户身份验证提供了大量默认值。为什么它不适用于有状态的 API 请求?

【问题讨论】:

    标签: spring-boot spring-mvc spring-security


    【解决方案1】:

    默认情况下,Spring Security 保护您免受跨站点请求伪造。

    如果你不想要它,你必须在你的配置中主动禁用它。

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            ...
    

    幸好你没有这样做,这样做不安全。

    但因此,您每次执行POST 时都需要提供一个csrf-token,在您的测试中也是如此!

    
    import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
    
    ...
    
    mockMvc.perform(post("/api/book")
           .with(csrf()) // <--- missing in your test
           .contentType(MediaType.APPLICATION_JSON)
           .content(payload))
           .andExpect(status().isCreated());
    
    

    现在你的测试应该可以工作了。

    【讨论】:

    • 你拯救了我的一天!谢谢!有时你无法想象这么简短的回答能节省多少时间……
    猜你喜欢
    • 2016-08-03
    • 2015-07-14
    • 2018-08-26
    • 2018-09-28
    • 2021-11-09
    • 2015-06-28
    • 1970-01-01
    • 2011-02-03
    • 1970-01-01
    相关资源
    最近更新 更多