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

如何将客户端证书转发至X.509认证的Spring Boot后端(WSO2 APIM场景)

解决WSO2 API Manager转发客户端X.509证书到后端服务的SSL握手问题

我来帮你拆解这个问题——你碰到的null cert chain和后续的Bad certificate错误,核心原因是WSO2网关没有正确接收并透传客户端的X.509证书到你的Spring Boot后端。结合你的多客户端场景,咱们一步步来解决:

先明确你的场景架构

你的需求是:客户端<->WSO2网关启用双向SSL,同时让WSO2仅把客户端的X.509证书转发给后端的Spring Boot服务(后端只验证客户端证书,不验证WSO2网关)。之前Postman直接调后端没问题,是因为Postman直接把客户端证书发给了后端;但接入WSO2后,网关没做好证书透传,才引发了SSL错误。

一、先解决"null cert chain"的根源:确保WSO2能拿到客户端证书

这个错误说明WSO2网关根本没收到客户端的证书,大概率是双向SSL配置没到位:

1. 用最新的deployment.toml配置双向SSL(别再改axis2.xml了)

WSO2现在推荐用repository/conf/deployment.toml做配置,避免老配置冲突。添加以下内容:

[transport.https.properties]
sslProtocol = "TLSv1.2"
enabled = true
port = 8243
keyStoreFile = "${carbon.home}/repository/resources/security/wso2carbon.jks"
keyStorePassword = "wso2carbon"
trustStoreFile = "${carbon.home}/repository/resources/security/client-truststore.jks"
trustStorePassword = "wso2carbon"
needClientAuth = "true"  # 强制客户端提供证书

2. 把客户端的CA证书导入WSO2信任库

WSO2要信任客户端的证书,必须把客户端证书的根CA导入到client-truststore.jks里(注意:不是后端服务的证书,后端证书是WSO2信任后端用的):

keytool -importcert -alias client-root-ca -file /path/to/client-ca.crt -keystore ${carbon.home}/repository/resources/security/client-truststore.jks -storepass wso2carbon

3. Postman调用WSO2时要带对证书

调用WSO2的API端点时,Postman里要导入客户端自己的证书(CRT+KEY+密码),而不是后端的证书!之前直接调后端用的是后端证书,现在调WSO2得换客户端证书。

二、解决"Bad certificate":确保证书能正确透传到后端

当WSO2能拿到客户端证书后,还需要把证书转发给后端。默认WSO2不会自动做这件事,得通过自定义中介实现:

1. 写一个自定义中介类提取并传递客户端证书

创建一个Java类,继承AbstractMediator,从SSL会话中提取客户端证书,然后设置到后端调用的上下文里:

import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.AbstractMediator;
import javax.net.ssl.SSLSession;
import java.security.cert.X509Certificate;

public class ClientCertForwardMediator extends AbstractMediator {
    @Override
    public boolean mediate(MessageContext context) {
        // 从WSO2的传输上下文里拿SSL会话
        SSLSession sslSession = (SSLSession) context.getProperty("TRANSPORT_SSL_SESSION");
        if (sslSession == null) {
            handleException("No SSL session found - client didn't send certificate?", context);
            return false;
        }

        try {
            // 获取客户端证书链
            X509Certificate[] clientCerts = (X509Certificate[]) sslSession.getPeerCertificates();
            if (clientCerts != null && clientCerts.length > 0) {
                // 把客户端证书存到上下文,供后端调用时使用
                context.setProperty("CLIENT_X509_CERT", clientCerts[0]);
                
                // 额外:如果后端需要通过HTTP头接收证书,可以把证书转成PEM格式放到Header里
                // String pemCert = "-----BEGIN CERTIFICATE-----\n" + Base64.getEncoder().encodeToString(clientCerts[0].getEncoded()) + "\n-----END CERTIFICATE-----";
                // context.setProperty("HTTP_HEADER_X-CLIENT-CERT", pemCert);
            }
        } catch (Exception e) {
            handleException("Failed to extract client certificate", e, context);
            return false;
        }
        return true;
    }
}

2. 部署自定义中介

把这个类打包成JAR,放到WSO2的repository/components/lib目录下,然后重启WSO2。

3. 在API的入流中添加这个中介

登录WSO2 APIM Publisher,编辑你的API:

  • 进入「Message Mediation」→「In Flow」
  • 添加一个「Class Mediator」,指定类名为你刚才写的com.your.package.ClientCertForwardMediator(替换成你的实际包名)

4. 配置后端调用时使用客户端证书

最后,要让WSO2在调用后端时使用刚才提取的客户端证书。可以通过配置后端端点的SSL上下文,或者在中介流中动态设置SSL参数。如果你的后端只验证客户端证书,那WSO2需要用客户端证书来和后端建立SSL连接:

  • 可以在deployment.toml中为后端配置动态SSL,或者使用WSO2的端点属性来指定证书。

三、验证步骤

  1. 重启WSO2和Spring Boot后端
  2. Postman导入客户端证书,调用WSO2的API端点
  3. 查看WSO2的日志,确认客户端证书被成功提取
  4. 查看Spring Boot后端的日志,确认收到的是客户端的X.509证书,而不是WSO2网关的证书

这样应该就能解决你的问题了——核心是确保WSO2先正确接收客户端证书,再通过自定义中介把证书透传给后端。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:22:55