You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于PACT JVM服务端请求添加OAuth2 Token的实现疑问

在Pact JVM中为请求添加OAuth2 Token的解决方案

嘿,我来帮你搞定Pact JVM里添加OAuth2 Token到请求头的问题!你已经成功在@BeforeClass里拿到了Token,现在只需要把它注入到Pact发送的请求里就行,@State方法其实是用来设置提供者的状态(比如让提供者模拟用户已登录的场景),不是用来修改消费者请求的,我给你两种靠谱的实现方式:

方法一:自定义HttpTarget添加请求拦截器

这种方法最直接,我们可以在初始化HttpTarget的时候,添加一个请求拦截器,让它在每个请求发送前自动把Token加到Authorization头里。

注意:为了确保Token已经获取到再初始化Target,我们可以把Target改成静态变量,在@BeforeClass里完成初始化:

public class TransactionPact { 
    private static Target target;
    private static FinanceApiToken financeApiToken; 

    @BeforeClass 
    public static void getAuthorisationToken() { 
        // 先获取OAuth2 Token
        HttpHeaders header = new HttpHeaders(); 
        header.set("Content-Type", "application/x-www-form-urlencoded"); 
        header.set("Authorization", "Basic ZmluLWFwaTphcGktc2VjcmV0"); 
        header.set("Connection", "keep-alive"); 
        header.set("cache-control", "no-cache"); 

        HttpEntity<String> request = new HttpEntity<>("username=sap&password=password2&grant_type=password", header); 
        RestTemplate restTemplate = new RestTemplate(); 
        ResponseEntity<FinanceApiToken> response = restTemplate.postForEntity("http://127.0.0.1:8080/oauth/token", request, FinanceApiToken.class); 

        if (response.getStatusCode() != HttpStatus.OK) { 
            throw new HTTPException(response.getStatusCodeValue()); 
        } 
        financeApiToken = response.getBody(); 

        // 初始化Target,添加请求拦截器注入Token
        target = new HttpTarget.Builder("http://localhost", 8332)
            .requestInterceptor((request, body, execution) -> {
                // 把Token以Bearer格式加到请求头
                request.getHeaders().set("Authorization", "Bearer " + financeApiToken.getAccessToken());
                return execution.execute(request, body);
            })
            .build();
    } 

    // 提供Target给Pact测试
    @TestTarget 
    public final Target getTarget() {
        return target;
    }

    @State("the consumer is authorised") 
    public void authorise() { 
        // 这里只需要处理提供者的状态,比如告诉提供者当前用户已授权
        // 比如如果是本地测试的提供者,可以在这里调用接口设置用户状态
    } 

    // 你的Pact测试方法示例
    @Pact(provider = "FinanceApi", consumer = "TransactionService")
    public RequestResponsePact createTransactionPact(PactDslWithProvider builder) {
        return builder
            .given("the consumer is authorised")
            .uponReceiving("a request to fetch user transactions")
            .path("/api/transactions")
            .method("GET")
            // 不需要手动加Authorization头,拦截器会自动处理
            .willRespondWith()
            .status(200)
            .body(PactDslJsonArray.arrayEachLike()
                .stringType("transactionId", "TXN-001")
                .numberType("amount", 500.00)
                .stringType("currency", "USD")
            )
            .toPact();
    }
}

方法二:全局请求过滤器(适用于所有Pact测试)

如果你的多个测试类都需要添加OAuth2 Token,可以用Pact的全局请求过滤器,一次性配置所有请求:

@BeforeClass 
public static void setupPactRequestFilter() { 
    // 先获取Token(和你原来的代码一样)
    // ...

    // 设置全局请求过滤器
    PactVerification.setRequestFilter(request -> {
        request.addHeader("Authorization", "Bearer " + financeApiToken.getAccessToken());
    });
}

这种方式会对当前类下的所有Pact请求生效,适合统一配置的场景。

关键说明

  • @State方法的核心作用是同步消费者和提供者的状态:比如你告诉提供者“现在消费者是已授权状态”,提供者需要模拟这个状态(比如在数据库中创建一个已登录的用户),而不是修改消费者的请求。
  • 拦截器/过滤器的方式能确保Token在请求发送前被注入,避免手动在每个Pact里重复添加头信息,也支持动态获取的Token。

内容的提问来源于stack exchange,提问作者sdicola

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:10:57