为安全控制器的集成测试设置身份验证

Posted

技术标签:

【中文标题】为安全控制器的集成测试设置身份验证【英文标题】:Set authentication for Integration test of secured Controller 【发布时间】:2020-05-23 11:55:45 【问题描述】:

我无法为我的 REST 控制器集成测试设置身份验证。 Controller的方法是这样的:

@RestController
@RequestMapping(BASE_URL)
@RequiredArgsConstructor
public class EventController 

    public static final String BASE_URL = "/api/event";

    @PostMapping
    @PreAuthorize("hasRole('USER')")
    public void createEvent() 
        System.out.println("I am in controller");
    

这是我的测试:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class EventControllerTest 

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @BeforeEach
    public void setup() 
        mockMvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply(springSecurity())
            .build();
    

    @Test
    void create() throws Exception 
        this.mockMvc.perform(post(EventController.BASE_URL)
            .with(authentication(new UsernamePasswordAuthenticationToken(
                new MyPrincipal(100, "denis"),
                null,
                Collections.singletonList(new SimpleGrantedAuthority("USER"))
            )))
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"));
    

由于401 状态,我的测试总是失败,所以我的模拟身份验证不起作用。你能告诉我如何解决吗?谢谢你的建议。

【问题讨论】:

身份验证如何在您的应用程序中工作? @SupunWijerathne 有基于 jwt 令牌的身份验证。 【参考方案1】:

测试安全请求的最简单方法是使用@WithMockUser(A_ROLE)

所以你的测试可能看起来像

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
@AutoConfigureMockMvc
class EventControllerTest 

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser("USER")
    void create() throws Exception 
        this.mockMvc.perform(post(EventController.BASE_URL)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().contentType("application/json"));
    

一些备注:

您的测试需要一个结果,因此请采用您的控制器或测试
    @PostMapping
    @PreAuthorize("hasRole('ROLE_USER')")
    public ResponseEntity<String> createEvent() 
        String result = "I am in controller";
        System.out.println(result);
        return ResponseEntity.ok().body(result);
    

您正在/正在测试POST,因此请确保在您的安全配置中您执行http.csrf().disable()....

或在您的测试中提供一个 csrf-token

 this.mockMvc.perform(post(EventController.BASE_URL)
         .with(SecurityMockMvcRequestPostProcessors.csrf()) // provide a csrf-token
         ....

'

【讨论】:

这总是给我 401 未授权 @DenisStephanov 改进了我的答案 same :/ 我们用于认证 oauth 令牌,这会导致这个问题吗? @DenisStephanov 这确实可以有所作为...不是我的领域,也许这个oauth-api-testing-with-spring-mvc 可以提供帮助

以上是关于为安全控制器的集成测试设置身份验证的主要内容,如果未能解决你的问题,请参考以下文章

在集成测试中使用 oauth/openid 进行身份验证

Symfony2 - 将安全访问控制设置为只允许匿名身份验证

使用集成 Windows 身份验证接收登录提示

请求规范中的存根身份验证

与 IIS、Firefox 和 SQL Server 集成的 Windows 身份验证

Spring安全缓存基本身份验证?不验证后续请求