Spring Security 和 MockMvc - 需要模拟身份验证或主体

标签 spring spring-security spring-security-oauth2 mockmvc

我正在使用 Spring Security,并面临为 Controller 编写单元测试用例(使用 MockMvc)的问题。

我的 Controller 中有一个方法,如下所示:

@GetMapping
public ResponseEntity<User> getUser(@AuthenticationPrincipal User activeUser){
    String userEmail = activeUser.getEmail();
    return userService.getUser(userEmail);
}

我收到了 500 错误。

我尝试过的 Controller 的另一个变体是,这适用于 Postman/Curl :

@GetMapping
public ResponseEntity<User> getUser(OAuth2Authentication authentication){
    String userEmail = (String) authentication.getUserAuthentication().getPrincipal();
    return userService.getUser(userEmail);
}

我的服务如下:

public ResponseEntity<User> getUser(String email) {
    return userRepository.findByEmail(email)
            .map(record -> ResponseEntity.ok().body(record))
            .orElse(ResponseEntity.notFound().build());
}

在此 Controller 方法的单元测试用例中,我有:

@Test
@WithMockUser(username = "1", password = "pwd", roles = "USER")
public void controller_should_get_user() throws Exception {
    when(userService.getUser("1")).thenReturn(new ResponseEntity(userMock, HttpStatus.OK));
    this.mockMvc.perform(MockMvcRequestBuilders.get("/api/user/")).andExpect(status().isOk());
}

我收到以下错误:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
at com.timecloud.user.controller.UserControllerTest.controller_should_get_user(UserControllerTest.java:60)

我应该如何使用当前身份验证传递或模拟用户?谢谢。

最佳答案

@WithMockUser创建 UsernameAuthenticationToken ,不是 OAuth2Authentication .

这里至少有三个解决方案:

  1. 注入(inject) OAuth2Authentication安全上下文中的模拟或实例
  2. 将您的方法更改为 public ResponseEntity<User> getUser(Authentication authentication) ,然后使用 authentication.getName()里面
  3. 使用一些现有工具来应用解决方案 1.对于你来说,就像这样 libs I wrote

解决方案 1 的使用示例

@Test
public void test() throws Exception {
    final var storedRequest = mock(OAuth2Request);

    final var principal = mock(Principal.class);
    when(principal.getName()).thenReturn("user");

    final var userAuthentication = mock(Authentication.class);
    when(userAuthentication.getAuthorities()).thenReturn(Set.of(new SimpleGrantedAuthority("ROLE_USER"));
    when(userAuthentication.getPrincipal()).thenReturn(principal);

    final var oauth2Authentication = new OAuth2Authentication(storedRequest, authentication);

    SecurityContextHolder.getContext().setAuthentication(oauth2Authentication);

    // use MockMvc to test a @Controller or unit-test any other secured @Component as usual
}

解决方案 3 的使用示例

@Test
@WithMockAuthentication(authType = OAuth2Authentication.class, name = "user", authorities = "ROLE_USER")
public void test() throws Exception {
    // use MockMvc to test a @Controller or unit-test any other secured @Component as usual
}

关于Spring Security 和 MockMvc - 需要模拟身份验证或主体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55155021/

相关文章:

java - JUnit 测试对 @transactional @Async 方法的调用导致超出锁等待超时

spring - Tomcat 中未拾取外部化的 message.properties 文件

java - 使用 Spring MVC 的嵌入式 Jetty

java - Spring 安全 "Remember Me"复选框

java - 用于验证来自 Google 的 oauth2 token 的 Spring Boot 应用程序

spring - 如何让 Spring oauth2 接受 application/json 的内容类型

java - Spring Security guest 用户

spring - 登录时清除 Spring session ?

一个应用程序中的 Spring Security OAuth2 和 FormLogin

grails - grails oauth2提供程序插件未按预期工作