【问题标题】:401 unauthorized when trying to get OAuth2 access token in jUnit尝试在 jUnit 中获取 OAuth2 访问令牌时出现 401 未授权
【发布时间】:2020-07-27 16:59:31
【问题描述】:

我需要编写一个 jUnit 测试用例,它总是因为“/contextpath/oauth2/token?grant_type=password”而失败。

@RunWith(SpringRunner.class)
@WebAppConfiguration
@AutoConfigureMockMvc
@SpringBootTest(classes = UserAuthApplication.class)
class UserAuthApplicationTests {

    
    @Autowired
    private MockMvc mockMvc;

    private String obtainAccessToken(final String username, final String password) throws Exception {

        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("grant_type", "password");
        params.add("username", username);
        params.add("password", password);

        ResultActions result = mockMvc
                .perform(post("/userauth/oauth/token").params(params).with(httpBasic("user-test","testp"))
                        .accept("application/json"))
                .andExpect(status().isOk())
                .andExpect((ResultMatcher) content());

        String resultString = result.andReturn().getResponse().getContentAsString();

        JacksonJsonParser jsonParser = new JacksonJsonParser();
        return jsonParser.parseMap(resultString).get("access_token").toString();
    }

    @Test
    public void tokenNotGiven_whenGetSecureRequest_thenUnauthorized() throws Exception {
        mockMvc.perform(get("/userauth/apis/v1/users").param("email", ""))
                .andExpect(status().isUnauthorized());
        
    }
    
    @Test
    public void givenValidUserCredentials_whenGetSecureRequest_thenAuthorized() throws Exception {
        String accessToken = obtainAccessToken("test@gmail.com", "test1");
        mockMvc.perform(get("/userauth/apis/v1/users")
          .header("Authorization", "Bearer " + accessToken)
          .param("email", ""))
          .andExpect(status().isOk());
        
        mockMvc.perform(get("/userauth/apis/v1/users")
              .header("Authorization", "Bearer " + accessToken)
              .param("email", ""))
              .andExpect(status().isOk())
            .andExpect((ResultMatcher) content().contentType("application/json;charset=UTF-8"))
            .andExpect(jsonPath("$.success", is(true)));
    }

}

当我在测试用例上运行时,它给了我以下错误:

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /userauth/oauth/token
       Parameters = {grant_type=[password], username=[test@gmail.com], password=[test1]}
          Headers = [Accept:"application/json", Authorization:"Basic dXNlci1hdXRoOm1hbm9q"]
             Body = null
    Session Attrs = {}

Handler:
             Type = null

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 401
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json", 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"]
     Content type = application/json
             Body = {"status":"UNAUTHORIZED","message":"Full authentication is required to access this resource"}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

预计它应该生成令牌,就像邮递员一样,即使在基于 ReactJS 的应用程序中也能够生成并正常工作,但它只在 jUnit 中失败。

【问题讨论】:

    标签: spring-boot junit junit5


    【解决方案1】:

    MockMvc 的好处是您使用模拟的 Servlet 环境和案例使用 Spring Security Test 支持基本上设置SecurityContext中的用户。如果您只是想要测试您的 HTTP 端点,这可以让您免于准备任何令牌。

    确保您的项目中具有以下依赖项:

    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-test</artifactId>
      <scope>test</scope>
    </dependency>
    

    然后您可以在测试方法级别使用@WithMockUser(username="mike"),或者在使用MockMvc 执行请求时:

    this.mockMvc
        .perform(get("/userauth/apis/v1/users")
          .with(SecurityMockMvcRequestPostProcessors.jwt()
            .jwt(YOUR_JWT_HERE) // also optional
            .authorities(new SimpleGrantedAuthority("ROLE_ADMIN")))) // also optional
        .andExpect(status().isOk());
    

    如果您仍想测试安全流程,我建议您在测试中使用@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 而不要使用MockMvc。然后您可以使用自动配置的TestRestTemplateWebTestClient 并首先执行令牌检索,然后使用真实 Servlet 环境访问您的端点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-29
      • 1970-01-01
      • 1970-01-01
      • 2021-08-22
      • 1970-01-01
      • 2019-04-15
      • 2013-05-17
      • 2021-08-20
      相关资源
      最近更新 更多