Spring Boot微服务JUnit测试-我如何从一个服务获得jwt令牌并在另一个服务中使用它 &



我有一个关于从一个服务中获取jwt令牌并在一个服务的测试方法中使用它的问题。

我试着写JUnit Controller test在支付,产品和订单服务在我的春季启动微服务的例子。在我定义了授权服务来处理创建用户和使用jwt登录之后令牌和定义api网关使用JWTFilter,需要定义承载令牌对于每个测试请求方法的每个请求

正常情况下,它的工作,但我必须得到jwt令牌和使用它,但我不知道如何得到它?

下面是PaymentControllerTest的一个测试方法。如您所见,没有授权承载者的定义。我怎么定义它呢?

@Test
@DisplayName("Place Order -- Success Scenario")
void test_When_placeOrder_DoPayment_Success() throws Exception {
OrderRequest orderRequest = getMockOrderRequest();
String jwt = getJWTTokenForRoleUser();
MvcResult mvcResult
= mockMvc.perform(MockMvcRequestBuilders.post("/order/placeorder")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.header("Authorization", "Bearer " + jwt)
.content(objectMapper.writeValueAsString(orderRequest)))
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
String orderId = mvcResult.getResponse().getContentAsString();
Optional<Order> order = orderRepository.findById(Long.valueOf(orderId));
assertTrue(order.isPresent());
Order o = order.get();
assertEquals(Long.parseLong(orderId), o.getId());
assertEquals("PLACED", o.getOrderStatus());
assertEquals(orderRequest.getTotalAmount(), o.getAmount());
assertEquals(orderRequest.getQuantity(), o.getQuantity());
}

以下是关于jwt令牌处理的方法

private String getJWTTokenForRoleUser(){
var loginRequest = new LoginRequest("User1","user1");
String jwt = jwtUtils.generateJwtToken(loginRequest.getUsername());
return jwt;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginRequest {
private String username;
private String password;
}

下面是jwtil类

@Component
public class JwtUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(JwtUtils.class);
@Value("${jwt.secret}")
private String jwtSecret;
@Value("${jwt.expireMs}")
private int jwtExpirationMs;
public String generateJwtToken(String username) {
return generateTokenFromUsername(username);
}
public String generateTokenFromUsername(String username) {
return Jwts.builder().setSubject(username).setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS512, jwtSecret).compact();
}
}

要运行应用程序,1)运行Service registry (Eureka Server)

2)运行config server

3)通过以下命令在docker

上运行zipkin和redis
docker run -d -p 9411:9411 openzipkin/zipkin 
docker run -d --name redis -p 6379:6379 redis

4)运行api gateway

5)运行认证服务、产品服务、订单服务和支付服务

(我在application-test中定义了所有属性。但是无法从OrderControllerTest)

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'jwt.secret' in value "${jwt.secret}"

这是repo: Link

您可以创建一个UTIL并从那里获得一个令牌,并在您的测试用例中使用

您不能使用模拟的jwt编写服务间测试:jwt是签名的,并且您无法访问授权服务器的私钥。

要么写

  • 在模拟HTTP环境中进行测试:@webMvcTest@SpringBootTest(webEnvironment = WebEnvironment.MOCK),在这种情况下,对其他服务的调用应该被模拟(使用wire mock或其他东西),因此将在测试安全上下文中进行身份验证(在这种情况下根本没有JWT)
  • "full"在所有服务启动的情况下进行集成测试,这是"真实的"。客户端(WebClient, RestTemplate, @FeignClient,或者用Protractor或其他东西操纵的实际UI)和真正的令牌(即由真实授权服务器颁发给真实用户)

第二种解决方案显然更复杂,学习、设置和维护的时间更长。此外,测试将变得更慢、更脆弱。广泛的"full"集成测试是一个地狱,经常被认为是最糟糕的实践。

您的项目甚至没有接近运行集成测试(没有父组件来管理模块间依赖关系和集成测试配置,错过配置的模块,…)

从单元测试开始:@WebMvcTest用于单个控制器,@MockBean用于使用@组件,如@Services和@Repository

然后编写范围为一个微服务的集成测试:@SpringBoot使用wiremock测试以模拟与其他微服务的交换。

也许只有这样,您才能编写包含几个微服务、一个授权服务器和一个"富"组件的完整集成测试。或REST客户端(如果您想模拟用户,则使用实用程序方法来执行授权代码流)。

现在,我强烈建议您关注前两种测试,遵循这些教程。同一个repo的示例还演示了如何使用安全表达式为@Services和@Repository编写单元测试。

最新更新