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

如何为Micronaut的JWKS端点配置WireMock动态端口避免测试冲突?

解决Micronaut测试中JWKS随机端口配置问题及替代方案

一、WireMock随机端口的正确配置方式

你之前在application.yaml中用${wiremock.server.port}无法解析,核心原因是Micronaut的配置加载时机早于WireMock启动,导致表达式无法获取到动态端口。正确的做法是在测试代码中动态注入配置:

  1. 启动WireMock时指定随机端口(用0表示)
  2. 在测试初始化阶段,将WireMock的实际端口拼接成JWKS URL,设置到Micronaut的环境配置中

示例代码(Java):

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import io.micronaut.context.env.Environment;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;

@MicronautTest
class JwtValidationTest {

    @Inject
    WireMockServer wireMockServer;

    @Inject
    Environment environment;

    @BeforeEach
    void setupJwksEndpoint() {
        // 动态生成JWKS URL并注入Micronaut配置
        String jwksUrl = String.format("http://localhost:%d/keys", wireMockServer.port());
        environment.put("micronaut.security.jwt.jwks.url", jwksUrl);

        // 配置WireMock返回合法的JWKS响应
        wireMockServer.stubFor(get(urlEqualTo("/keys"))
                .willReturn(aResponse()
                        .withHeader("Content-Type", "application/json")
                        .withBody("{\"keys\": [你的JWKS密钥内容]}")));
    }

    @Test
    void testJwtValidation() {
        // 测试逻辑:生成使用WireMock中密钥签名的JWT,调用接口验证
    }
}

注意:需要确保WireMock的依赖正确引入,并且测试类中已配置WireMock的启动(比如用@WireMockTest注解或手动初始化WireMockServer)。

二、不使用WireMock的替代方案

方案1:本地生成密钥对,跳过JWKS依赖

直接在测试中生成RSA密钥对,配置Micronaut使用本地公钥验证JWT,用私钥签名测试用的JWT,完全不需要外部JWKS服务:

import io.micronaut.context.env.Environment;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@MicronautTest
class LocalKeyJwtTest {

    @Inject
    Environment environment;
    private RSAPrivateKey privateKey;

    @BeforeEach
    void setupLocalKeys() throws NoSuchAlgorithmException {
        // 生成RSA密钥对
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        KeyPair keyPair = keyGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        privateKey = (RSAPrivateKey) keyPair.getPrivate();

        // 配置Micronaut使用本地公钥验证JWT
        environment.put("micronaut.security.jwt.signatures.jwt.rsa.public-key", publicKey);
    }

    @Test
    void testLocalJwtValidation() {
        // 用私钥生成测试JWT
        String jwt = Jwts.builder()
                .subject("test-user")
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .compact();

        // 携带JWT调用接口验证
    }
}

方案2:使用Micronaut测试注解模拟认证

如果你的测试不需要验证JWT签名的合法性,只是需要模拟已认证的用户状态,可以直接用@JwtAuthentication注解跳过签名验证:

import io.micronaut.http.HttpResponse;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.client.HttpClient;
import io.micronaut.test.annotation.JwtAuthentication;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

@MicronautTest
class MockAuthTest {

    @Inject
    HttpClient client;

    @Test
    @JwtAuthentication(subject = "test-user", roles = {"admin"})
    void testProtectedEndpoint() {
        HttpResponse<String> response = client.toBlocking()
                .exchange("/admin/endpoint", String.class);
        assertEquals(HttpStatus.OK, response.status());
    }
}

这个方案最简洁,但仅适用于不需要实际验证JWT签名的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:43:16