Spring微服务调用自签名证书HTTPS端点报错求助
解决"No subject alternative names present" HTTPS连接异常
错误原因
服务器使用的自签名证书未配置主题备用名称(Subject Alternative Name,SAN)。JVM在HTTPS握手时,会验证证书的SAN字段是否包含请求的域名/IP,若缺失则抛出该异常。
解决方案
方案1:重新生成带SAN的自签名证书(生产环境推荐)
若有权限修改服务器证书,这是最规范的解决方式:
- 创建
san.cnf配置文件,指定证书的SAN信息:[req] distinguished_name = req_distinguished_name req_extensions = v3_req prompt = no [req_distinguished_name] CN = your-server-hostname-or-ip [v3_req] keyUsage = keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = your-server-hostname # 替换为服务器域名 IP.1 = your-server-ip-address # 替换为服务器IP - 用OpenSSL生成带SAN的自签名证书:
openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes -config san.cnf - 替换服务器上的旧证书,重新将新证书导入JVM信任库:
sudo keytool -importcert -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit -file server.crt -alias "server_remote-root"
方案2:修改本地hosts映射(测试/内部环境适用)
若通过IP访问服务器,可将IP映射到证书的CN域名:
- 打开本地hosts文件:
- Linux/macOS:
/etc/hosts - Windows:
C:\Windows\System32\drivers\etc\hosts
- Linux/macOS:
- 添加映射规则:
your-server-ip your-server-hostname - 微服务中使用
your-server-hostname代替IP访问API端点,让请求域名与证书CN匹配。
方案3:自定义TrustManager跳过SAN验证(不推荐生产环境)
若无法修改证书或hosts,可通过代码跳过主机名验证(注意:此操作会降低安全性,仅用于内部可信环境):
在Spring中自定义RestTemplate:
import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.ssl.SSLContexts; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; import javax.net.ssl.SSLContext; import java.security.KeyStore; public class CustomRestTemplateConfig { public RestTemplate createRestTemplate() throws Exception { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(trustStore, (chain, authType) -> true) .build(); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( sslContext, NoopHostnameVerifier.INSTANCE ); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); factory.setHttpClient(org.apache.http.impl.client.HttpClients.custom() .setSSLSocketFactory(socketFactory) .build()); return new RestTemplate(factory); } }
注册该RestTemplate到Spring容器,用于调用目标API。
内容的提问来源于stack exchange,提问作者Domenico Scelza
相关产品推荐
相关产品推荐

