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

X509证书自定义验证(特定路径):单请求/用户的双向SSL适配问题

针对单个请求实现自签名CA证书验证的方案

我完全懂你的痛点——全局开双向SSL太一刀切,只想对那个特定服务提供商的请求做证书验证,其他服务完全不受影响。既然已经关掉了全局双向SSL,那咱们就把验证逻辑精准放到控制器里来实现,具体可以这么做:

1. 先准备好自签名根CA证书

把服务提供商给你的自签名根CA证书放到项目的资源目录(比如src/main/resources/certs),方便后续代码里加载使用。

2. 构建自定义信任管理器

手动创建一个只包含这个根CA的信任管理器,这样咱们的代码就只会信任由这个根CA签发的客户端证书:

private TrustManager[] getCustomTrustManager() throws Exception {
    // 加载根CA证书文件
    InputStream caInput = new ClassPathResource("certs/rootCA.crt").getInputStream();
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    X509Certificate caCert = (X509Certificate) cf.generateCertificate(caInput);
    caInput.close();

    // 创建专属信任库并添加根CA
    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    trustStore.load(null, null);
    trustStore.setCertificateEntry("service-provider-root-ca", caCert);

    // 初始化信任管理器
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(trustStore);
    return tmf.getTrustManagers();
}

3. 在目标控制器方法里做证书验证

当那个服务提供商的请求进来时,先从请求里提取客户端证书,再用咱们的自定义信任管理器去验证,确保是合法的:

@PostMapping("/provider-only-api")
public ResponseEntity<String> handleProviderRequest(HttpServletRequest request) {
    try {
        // 从请求属性中获取客户端证书链
        X509Certificate[] clientCerts = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
        
        if (clientCerts == null || clientCerts.length == 0) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("未提供合法客户端证书");
        }

        // 获取自定义信任管理器
        X509TrustManager customTrustManager = (X509TrustManager) getCustomTrustManager()[0];

        // 核心验证:检查证书是否由指定根CA签发
        customTrustManager.checkClientTrusted(clientCerts, "RSA");

        // 可选:再加一层精准校验,比如验证证书的主题信息是否匹配服务商
        X509Certificate clientCert = clientCerts[0];
        if (!clientCert.getSubjectDN().getName().contains("CN=指定服务商标识")) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("证书主体不符合要求");
        }

        // 验证通过,处理业务逻辑
        return ResponseEntity.ok("请求处理成功");
    } catch (CertificateException e) {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("证书验证失败:" + e.getMessage());
    } catch (Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务处理出错");
    }
}

4. 关键配置注意事项

要确保你的Web服务器(比如Tomcat)在关闭强制双向SSL的情况下,依然能接收客户端证书。如果是Spring Boot项目,可以在application.properties里这么配:

# 服务器自身的SSL配置还是要保留
server.ssl.key-store=classpath:your-server-keystore.jks
server.ssl.key-store-password=your-keystore-pwd
# 设置为want,服务器会请求证书但不强制,有证书就接收
server.ssl.client-auth=want

这样一来,只有访问/provider-only-api的请求会触发证书验证,其他所有请求都完全不受影响,完美实现了你要的“单个请求/用户应用验证”的需求~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:46:27