spring-boot - 尝试在 jUnit 中获取 OAuth2 访问令牌时出现 401 未授权
问题描述
我需要编写一个 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 中失败。
解决方案
这样做的好处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
. 然后您可以使用自动配置TestRestTemplate
或WebTestClient
首先执行令牌检索,然后使用真实的Servlet 环境访问您的端点。
推荐阅读
- mysql - 当列名与 SQL 相同时如何进行 GROUP BY 和求和?
- deep-learning - 我是否正确实施了学习率查找器?
- javascript - javascript步入对象以填充变量
- java - 如何从具有 Apache POI 的公式字段的 Excel 单元格中读取确切的日期格式?
- python - 从 pandas Dataframe 到 15minute Bins 中的数据帧时间序列(按总和行)
- python - 当文件中的任何代码更改时,应运行 Python 自动化脚本
- python - 返回几个月前开始的月份数字列表
- ios - 使用 Uiapplication() 与观察者互动时出现问题
- symfony - Symfony4:了解目录 public/bundles
- swift - “在从主线程访问引擎后,此应用程序正在从后台线程修改自动布局引擎”在 Swift 中