RestTemplate Https 证书访问错误

错误信息

resttemplate I/O error on GET request for "https://21.24.6.6:9443/authn-api/v5/oauth/token": java.security.cert.CertificateException: No subject alternative names present; nested exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present

这个错误是由于 SSL/TLS 握手失败引起的,具体原因是服务器的 SSL 证书无效或不受信任。错误信息 No subject alternative names present 表示服务器的证书中没有包含与请求的域名匹配的主题备用名称(Subject Alternative Name, SAN)。

以下是解决此问题的几种方法:

1. 检查服务器证书

确保服务器的 SSL 证书是有效的,并且包含正确的主机名(即请求的域名)。可以通过以下步骤检查证书:

  • 使用浏览器访问服务器的 URL(例如 https://21.24.6.6:9443),查看证书的详细信息。

  • 确保证书的 Subject Alternative Name (SAN) 包含请求的域名或 IP 地址。

如果证书无效或不匹配,需要联系服务器管理员更新证书。

2. 忽略 SSL 证书验证(仅用于测试环境)

在生产环境中不建议使用此方法,但在测试环境中可以临时忽略 SSL 证书验证。

使用 RestTemplate 忽略 SSL 验证

java 复制代码
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

public class RestTemplateExample {

    public static void main(String[] args) throws Exception {
        // 创建忽略 SSL 验证的 RestTemplate
        RestTemplate restTemplate = createRestTemplateWithIgnoreSSL();

        // 发送请求
        String url = "https://21.24.6.6:9443/authn-api/v5/oauth/token";
        String response = restTemplate.getForObject(url, String.class);
        System.out.println("Response: " + response);
    }

    private static RestTemplate createRestTemplateWithIgnoreSSL() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        // 创建 SSLContext,忽略证书验证
        SSLContext sslContext = new SSLContextBuilder()
                .loadTrustMaterial(null, (certificate, authType) -> true) // 信任所有证书
                .build();

        // 创建 HttpClient
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLContext(sslContext)
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) // 忽略主机名验证
                .build();

        // 创建 RestTemplate
        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(requestFactory);
    }
}

3. 使用自定义信任库

如果服务器使用的是自签名证书或私有 CA 签发的证书,可以将证书导入 Java 的信任库(cacerts)或自定义信任库。

步骤:

  1. 导出服务器的证书:

    • 使用浏览器访问服务器的 URL,导出证书(通常为 .crt 或 .pem 格式)。

    • 或者使用 openssl 命令导出证书:

bash 复制代码
openssl s_client -connect 21.24.6.6:9443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM > server.crt
  1. 将证书导入 Java 信任库:
    • 找到 Java 的默认信任库(通常位于$JAVA_HOME/lib/security/cacerts)。

    • 使用 keytool 将证书导入信任库:

bash 复制代码
keytool -import -trustcacerts -file server.crt -keystore $JAVA_HOME/lib/security/cacerts -alias server_cert
复制代码
- 默认密码是 changeit。
  1. 配置 RestTemplate 使用自定义信任库:
java 复制代码
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.security.KeyStore;

public class RestTemplateExample {

    public static void main(String[] args) throws Exception {
        // 创建使用自定义信任库的 RestTemplate
        RestTemplate restTemplate = createRestTemplateWithCustomTrustStore();

        // 发送请求
        String url = "https://21.24.6.6:9443/authn-api/v5/oauth/token";
        String response = restTemplate.getForObject(url, String.class);
        System.out.println("Response: " + response);
    }

    private static RestTemplate createRestTemplateWithCustomTrustStore() throws Exception {
        // 加载自定义信任库
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        try (FileInputStream fis = new FileInputStream("path/to/truststore.jks")) {
            trustStore.load(fis, "password".toCharArray());
        }

        // 创建 SSLContext
        SSLContext sslContext = new SSLContextBuilder()
                .loadTrustMaterial(trustStore, null) // 使用自定义信任库
                .build();

        // 创建 HttpClient
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLContext(sslContext)
                .build();

        // 创建 RestTemplate
        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(requestFactory);
    }
}

4. 检查服务器配置

如果服务器配置了 SNI(Server Name Indication),确保客户端支持 SNI。某些旧版本的 Java 可能不支持 SNI,可以尝试升级 Java 版本。

5. 使用 WebClient 替代 RestTemplate

如果使用的是 Spring WebFlux,可以考虑使用 WebClient,它提供了更灵活的 SSL 配置选项。

示例:

java 复制代码
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

public class WebClientExample {

    public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException {
        // 创建忽略 SSL 验证的 WebClient
        WebClient webClient = WebClient.builder()
                .baseUrl("https://21.24.6.6:9443")
                .build();

        // 发送请求
        Mono<String> response = webClient.get()
                .uri("/authn-api/v5/oauth/token")
                .retrieve()
                .bodyToMono(String.class);

        response.subscribe(body -> System.out.println("Response: " + body));
    }
}

总结

  • 如果服务器证书无效或不匹配,需要更新证书。
  • 在测试环境中可以临时忽略 SSL 验证,但不建议在生产环境中使用。
  • 对于自签名证书或私有 CA 签发的证书,可以将证书导入 Java 信任库或自定义信任库。
  • 如果问题仍然存在,可以尝试使用 WebClient 替代 RestTemplate。
相关推荐
00后程序员张4 小时前
抓包鹰 电脑本机网络连接表怎么看?哪些程序在联网 进程归属与可疑 IP 追溯
网络协议·计算机网络·网络安全·ios·adb·https·udp
2501_915106329 小时前
iOS 证书类型及作用说明 账号证书与签名配置的完整解读
android·ios·小程序·https·uni-app·iphone·webview
DsirNg10 小时前
一文讲清网络协议:从打开网页到理解 HTTP、HTTPS 与 TLS
http·https·dns·网络基础·入门教程·tls·web 安全
奈斯先生Vector10 小时前
2026 AIGC API 网关韧性评测:为什么 HTTP 200 不等于有效交付
网络协议·http·aigc
拾光Ծ12 小时前
【Linux网络】深入理解网络层:从IP协议格式,子网划分到NAT与路由机制
linux·网络·网络协议·tcp/ip·计算机网络
谏书稀12 小时前
C++/Python 混合编程(CPython)中 GIL饥饿 导致的 HTTP 服务无响应问题与解决方案
c++·python·http
全麦面包 time展天1 天前
瀚海拾贝(一)HTTP协议/IIS 原理及ASP.NET运行机制浅析【图解】
网络协议·http·asp.net
微硬创新1 天前
耐达讯自动化16路0-20mA转PROFINET协议转换模块技术说明
人工智能·网络协议·自动化·信息与通信
2501_915918411 天前
iOS 怎么抓包?抓包鹰系统级 网卡 应用层三种方式对比,不越狱抓 iPhone 流量
网络协议·计算机网络·网络安全·ios·adb·https·udp
March.s1 天前
IP 存储核心 iSCSI:原理拆解 + 无报错实战指南
网络·网络协议·tcp/ip