SSL双向认证连接抛出NoSuchAlgorithmException问题求助
连接双向认证Web服务时Web应用抛出NoSuchAlgorithmException(Java应用正常)
我在连接一个需要客户端/服务端双向认证的Web服务时,抛出了NoSuchAlgorithmException异常。相同代码作为标准Java应用运行完全正常,但部署成Web应用运行时就会触发这个异常,求解决思路。
代码示例
try { System.setProperty("javax.net.debug", "ssl,handshake"); System.setProperty("javax.net.ssl.keyStoreType", "pkcs12"); System.setProperty("javax.net.ssl.keyStore", "c:\\Sifen\\F1T_5159.p12"); System.setProperty("javax.net.ssl.keyStorePassword", "password"); String soapRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:xsd=\"http://ekuatia.set.gov.py/sifen/xsd\">\n" + "<soap:Header/>\n" + "<soap:Body>\n" + "<xsd:rEnviConsRUC xmlns=\"http://ekuatia.set.gov.py/sifen/xsd\"\n" + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + " xsi:schemaLocation=\"http://ekuatia.set.gov.py/sifen/xsd/ siConsRUC_v150.xsd\">\n" + " <xsd:dId>1</xsd:dId>\n" + " <xsd:dRUCCons>80033703</xsd:dRUCCons>\n" + "</xsd:rEnviConsRUC>\n" + "</soap:Body>\n" + "</soap:Envelope>"; String url = "https://sifen-test.set.gov.py/de/ws/consultas/consulta-ruc.wsdl"; URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "text/xml; charset=utf-8"); con.setDoOutput(true); try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) { wr.writeBytes(soapRequest); wr.flush(); } String responseStatus = con.getResponseMessage(); System.out.println(responseStatus); BufferedReader in = new BufferedReader(new InputStreamReader( con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); String finalvalue = response.toString(); System.out.println(finalvalue); } catch (Exception e) { System.out.println(e.getMessage()); }
异常信息
java.security.NoSuchAlgorithmException: 构造实现时出错(算法: Default,提供者: SunJSSE,类: sun.security.ssl.SSLContextImpl$DefaultSSLContext)
解决思路
- 排查类加载冲突:Web容器的类加载机制和标准Java应用不同,检查Web应用依赖中是否包含第三方SSL/Crypto相关jar包(比如
bcprov-jdkxx等),这类jar会覆盖JRE自带的SunJSSE实现,导致算法找不到。移除冲突jar即可。 - 提前设置系统属性:Web应用中通过
System.setProperty设置SSL属性的时机可能太晚,建议在Web应用启动初期(比如ServletContextListener的contextInitialized方法)设置,或者直接在Web容器启动参数中配置(如Tomcat的catalina.sh添加-Djavax.net.ssl.keyStore=xxx等参数)。 - 修正密钥库路径与权限:Web应用运行的工作目录和本地Java应用不同,即使使用绝对路径,也可能因容器权限限制无法读取密钥库。可以将密钥库放到Web应用资源目录,通过类加载器获取路径:
Thread.currentThread().getContextClassLoader().getResource("F1T_5159.p12").getPath(),同时确保容器进程有读取该文件的权限。 - 统一JRE版本:检查Web容器使用的JRE版本和本地运行的JRE是否一致,部分旧版JRE对SSL算法支持不足,或默认Provider配置不同。
- 手动初始化SSLContext:不依赖默认SSLContext,手动构建SSL上下文并绑定到连接,避免容器默认配置干扰:
KeyStore keyStore = KeyStore.getInstance("PKCS12"); try (InputStream is = new FileInputStream("c:\\Sifen\\F1T_5159.p12")) { keyStore.load(is, "password".toCharArray()); } KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, "password".toCharArray()); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), null, null); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
内容的提问来源于stack exchange,提问作者César
相关产品推荐
相关产品推荐

