【发布时间】:2020-05-21 22:23:03
【问题描述】:
我有一个使用 HTTPS 协议在本地运行的带有自签名证书的 Spring Boot API。
显然,当我从浏览器发送GET请求时,我在服务器端收到io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown错误,这是正常的,因为自签名不被浏览器信任。邮递员适用于 GET 和 POST。
但是,我想从 Android 客户端向 Spring API 发送 GET 请求,但是,即使我使用了允许所有 SSL 流量的函数(是的,我知道不推荐),我仍然不能向 API 发送请求,接收以下输出:
I/STATUS: 405
I/MSG: Method Not Allowed
我认为我的allowAllSSL() 函数(HttpsTrustManager 类)会解决问题,因为如果我删除函数调用,我会收到以下错误,这似乎与服务器端的错误匹配:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:239)
现在,您可能认为 GET 请求在 Spring 中没有正确实现,但事实并非如此,因为同样的 GET 请求在 Postman 中也可以正常工作。我相信问题仍然与证书有关,但我无法弄清楚我需要更改什么。这是我的代码:
Spring BOOT 休息控制器
@RestController
@RequestMapping("/post")
public class PostRequest {
@GetMapping("")
public String string(@RequestBody ImageRequest newEmployee){
....
ImageRequest 类仅包含三个私有 String 成员。
HttpsTrustManager 类(允许所有 SSL)
package com.example.androidclient;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class HttpsTrustManager implements X509TrustManager {
private static TrustManager[] trustManagers;
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};
@Override
public void checkClientTrusted(
X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(
X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
public boolean isClientTrusted(X509Certificate[] chain) {
return true;
}
public boolean isServerTrusted(X509Certificate[] chain) {
return true;
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return _AcceptedIssuers;
}
public static void allowAllSSL() {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
SSLContext context = null;
if (trustManagers == null) {
trustManagers = new TrustManager[]{new HttpsTrustManager()};
}
try {
context = SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
HttpsURLConnection.setDefaultSSLSocketFactory(context != null ? context.getSocketFactory() : null);
}
}
Android 请求
HttpsTrustManager.allowAllSSL();
URL url = new URL("https://192.168.1.106:8443/post");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true);
conn.setDoInput(true);
JSONObject jsonParam = new JSONObject();
jsonParam.put("location", "Somewhere");
jsonParam.put("date", "22.05.2020");
jsonParam.put("imageBytes", strings[0]);
Log.i("JSON", jsonParam.toString());
DataOutputStream os = new DataOutputStream(conn.getOutputStream());
//os.writeBytes(URLEncoder.encode(jsonParam.toString(), "UTF-8"));
os.writeBytes(jsonParam.toString());
os.flush();
os.close();
Log.i("STATUS", String.valueOf(conn.getResponseCode()));
Log.i("MSG", conn.getResponseMessage());
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
return "ok";
}
【问题讨论】:
标签: java android spring spring-boot ssl