我在刷新令牌和注销中使用不记名令牌有问题,因为在Sping Boot 示例的集成测试中,所有这两个过程都是用不记名令牌处理的。
我创建了MockJwtTokenProvider来为下面所示的集成测试创建一个模拟承载令牌
public class MockJwtTokenProvider {
private static final String SECRET_KEY = "404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970";
public static final long EXPIRATION_TIME_MS = 3600000; // 1 hour
public static String createMockJwtTokenForCustomer() {
Claims claims = Jwts.claims()
.setSubject("customer_1") // Set the username as the subject
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + MockJwtTokenProvider.EXPIRATION_TIME_MS));
claims.put("roles", Collections.singletonList("ROLE_CUSTOMER"));
claims.put("userFullName", "customer_fullname");
claims.put("id", 1);
claims.put("email", "[email protected]");
// Create a secret key from your actual secret key string
SecretKey secretKey = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
// Build the JWT token with the provided claims
String token = Jwts.builder()
.setClaims(claims)
.setIssuedAt(new Date())
.signWith(secretKey, SignatureAlgorithm.HS512)
.compact();
return "Bearer " + token;
}
}
下面是AuthControllerTest的相关部分
@Test
void refreshToken_ReturnSuccess() throws Exception {
// given
TokenRefreshRequest request = TokenRefreshRequest.builder()
.refreshToken("validRefreshToken")
.build();
TokenRefreshResponse mockResponse = TokenRefreshResponse.builder()
.accessToken("newMockedToken")
.refreshToken("validRefreshToken")
.build();
String mockBearerToken = MockJwtTokenProvider.createMockJwtTokenForCustomer();
// when
when(authService.refreshToken(request)).thenReturn(mockResponse);
// then
mockMvc.perform(post("/api/v1/auth/refreshtoken")
.header("Authorization", mockBearerToken)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
@Test
void logout_ReturnSuccess() throws Exception {
// Given
String mockBearerToken = MockJwtTokenProvider.createMockJwtTokenForCustomer();
// When
when(authService.logout(mockBearerToken)).thenReturn("success");
// Then
mockMvc.perform(post("/api/v1/auth/logout")
.header("Authorization", mockBearerToken))
.andExpect(status().isOk());
verify(authService).logout(mockBearerToken);
}
我总是得到这个问题如下所示的刷新令牌和注销。
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:"0", 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 = {"path":"","error":"Unauthorized","message":"Full authentication is required to access this resource","status":401}
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status expected:<200> but was:<401>
Expected :200
Actual :401
我也使用真实的不记名令牌,但我得到了同样的错误。
我如何解决这个问题?
下面是repo:Link
2条答案
按热度按时间e1xvtsh31#
[更新]基于your github repository,我看到,在xml 2中,您正在使用另一个实用程序类
JwtUtils
,它与MockJwtTokenProvider
没有相同的结构和内容!我想这就是你的问题背后的原因。下面是 JwtUtils 类,它在运行时工作正常:
我尝试在调试模式下运行测试,并注意到一个异常:
也就是说密钥和加密算法不兼容。尝试在测试中使用
JwtUtils
,你会没事的。此外,由于您正在使用spring-security-test,因此必须使用
@WithMockUser
注解定义一个mock user。检查以下示例:bakd9h0s2#
我也是通过这种方法解决了这个问题。
1 .在AuthControllerTest中定义customUserDetailsService和jwtUtils
2 .定义bearer token
3 .由于我通过testcontainer在docker上运行mysql,找不到值,返回userDetails,使用mock
下面是最终代码