Spring Boot Sping Boot 微服务JUnit测试-如何从一个服务获取jwt令牌并将其用于另一个服务

kq0g1dla  于 2022-11-23  发布在  Spring
关注(0)|答案(2)|浏览(145)

我遇到了一个关于从一个服务获取JWT令牌并在一个服务的测试方法中使用它的问题。
在我的spring boot微服务示例中,我尝试在支付、产品和订单服务中编写JUnit Controller test,在我定义了auth服务来处理创建用户和使用jwttoken登录,并定义了api网关来使用JWTFilter之后,需要为每个测试请求方法的每个请求定义bearer token
通常,它的工作,但我必须得到jwt令牌和使用它,但我不知道如何得到它?
下面是PaymentControllerTest的一个测试方法,可以看到没有定义Authorization Bearer,如何定义?

@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;

}

下面是jwtutil类

@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)**运行服务注册表(Eureka服务器)

    • 2)**运行配置服务器
    • 3)**在docker上通过以下命令运行zipkin和redis
docker run -d -p 9411:9411 openzipkin/zipkin 
docker run -d --name redis -p 6379:6379 redis
    • 4)**运行api网关
    • 5)**运行认证服务、产品服务、订单服务和支付服务
    • 已编辑**(我在application-test. yaml中定义了所有属性,但无法从OrderControllerTest中提取它们)
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'jwt.secret' in value "${jwt.secret}"

下面是回购协议:Link

628mspwn

628mspwn1#

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

6fe3ivhb

6fe3ivhb2#

您不能使用模拟的JWT编写服务间测试:JWT已签名,您将无法访问授权服务器私钥。
要么写

  • 模拟HTTP环境中的测试:@webMvcTest@SpringBootTest(webEnvironment = WebEnvironment.MOCK),在这种情况下,应该模拟对其他服务的调用(使用wire mock或其他方法),因此将在测试安全上下文中进行身份验证(在这种情况下,根本没有JWT)
  • “完整”集成测试,所有服务均已启动,一个“真实的”客户端(WebClient、RestTemplate、@FeignClient或使用量角器等操作的实际UI)和真实令牌(由真实授权服务器为真实用户颁发)

第二种解决方案显然更复杂,学习、设置和维护时间更长。而且,测试速度更慢,也更脆弱。广泛的“完全”集成测试是一个地狱,经常被认为是最糟糕的做法。
Your project甚至不接近运行集成测试(没有父POM来管理模块间依赖关系和集成测试配置,缺少已配置的模块...)
从单元测试开始:@WebMvcTest用于单个@Controller,@MockBean用于已使用的@Services和@Repository等组件
然后编写一个微服务范围内的集成测试:@SpringBoot使用wirerock进行测试,以模拟与其他微服务的交换。
也许只有到那时,您才能编写涉及多个微服务、一个授权服务器和一个“富”或REST客户端(如果您想模拟用户,则使用一个实用程序方法来遍历授权代码流)的完整集成测试。
现在,我强烈建议您关注those tutorials之后的前两种测试。samples of the same repo还演示了如何使用安全表达式为@Services和@Repository编写单元测试。

相关问题