Ich habe den Code zum Aufrufen der REST-API mit SSL unter Verwendung von OkHttp3 geschrieben. Es gibt viele Beispiele auf der Welt, die eine Verbindung herstellen, ohne das Zertifikat zu validieren. Dieser Code führt jedoch die folgende Validierung durch.
Beziehen Sie das Serverzertifikat von dem Ort, an dem die API veröffentlicht wird. Diesmal habe ich es von Recruit im Browser (Chrome) bekommen. Sie können verschiedene Möglichkeiten finden, um es zu erhalten, indem Sie nach "So erhalten Sie einen Serverzertifikat-Browser" suchen. Das Format der Exportdatei lautet "Base 64-codiertes X.509".
Es ist das über dem Zertifikat im "Zertifizierungspfad". Holen Sie es sich auf die gleiche Weise wie oben.
Öffnen Sie die beiden oben genannten Zertifikate mit einem Texteditor und kopieren Sie eines davon und fügen Sie es in eines ein. Ich habe die Eltern als "Zertifizierungspass" gestürzt.
Stellen Sie die zusammengeführten Dateien an einem Speicherort in Ihrem Klassenpfad bereit.
API(SSL)Ausführungsklasse
public class RestSecureApiExecutor extends RestApiExecutor {
private CertificateManager certMgr;
/**
*Konstrukteur.
*
* @param apiAttr Secure API-Attribut
*/
public RestSecureApiExecutor(SecureApiAttribute apiAttr) {
super(apiAttr);
this.certMgr = apiAttr.getCertMgr();
}
/**
* {@inheritDoc}
*/
@Override
public Response get(Map<String, String> header, Map<String, String> param, boolean isValidCache) throws IOException {
//URL-Assembly
HttpUrl.Builder urlBuilder = createUrlBuilder(ProtocolType.Secure, param);
//HTTP-Header zusammenstellen
Request.Builder requestBuilder = createRequestBuilder(header);
//Gibt an, ob der Cache verwendet werden soll
if (!isValidCache) {
requestBuilder.cacheControl(new CacheControl.Builder().noCache().noStore().maxAge(0, TimeUnit.SECONDS).build());
}
//Die Anfrage zusammenstellen
Request request = requestBuilder.url(urlBuilder.build()).build();
//Gibt an, ob der Cache verwendet werden soll
OkHttpClient.Builder clientBuilder = createClientBuilder(isValidCache);
addCertificatePinner(clientBuilder, certMgr.getCertificates());
addSslSocketFactory(clientBuilder, certMgr.getTrustManager());
//API-Ausführung
return clientBuilder.build().newCall(request).execute();
}
/**
*Fügen Sie dem Builder CertificatePinner hinzu.
*
* @param builder OkHttpClient.Builder-Objekt
* @param-Zertifikate Zertifikatinformationen
*/
private void addCertificatePinner(OkHttpClient.Builder builder, Certificate[] certificates) {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(this.hostname, CertificatePinner.pin(certificates[0]))
.build();
builder.certificatePinner(certificatePinner);
}
/**
*Fügen Sie dem Builder SslSocketFactory hinzu.
*
* @param builder OkHttpClient.Builder-Objekt
* @param trustManager TrustManager
*/
private void addSslSocketFactory(OkHttpClient.Builder builder, X509TrustManager trustManager) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { trustManager }, null);
builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException("____ failed to create ssl socket factory.", e);
}
}
Elternklasse
public class RestApiExecutor {
/**
*Protokolltyp.
*/
public enum ProtocolType {
/**Normal. */
Normal("http"),
/** SSL. */
Secure("https"),;
private String type;
private ProtocolType(String type) {
this.type = type;
}
public String getValue() {
return this.type;
}
}
/**Hostname. */
protected String hostname;
/**Segment. */
protected String segment;
/**
*Konstrukteur.
*
* @param apiAttr API-Attribut
*/
public RestApiExecutor(ApiAttribute apiAttr) {
//Hostname, Segment
this.hostname = apiAttr.getHostname();
this.segment = apiAttr.getSegment();
}
/**
* REST API (get)Laufen.
*
* @Parameter-Header HTTP-Header-Parameter
* @param param Abfrageparameter
* @param isValidCache Cache verwenden (true: use, false: not use)
* @Antwort zurückgeben
* @löst IOException aus Wenn die Verarbeitung fehlschlägt
*/
public Response get(Map<String, String> header, Map<String, String> param, boolean isValidCache) throws IOException {
//URL-Assembly
HttpUrl.Builder urlBuilder = createUrlBuilder(ProtocolType.Normal, param);
//HTTP-Header zusammenstellen
Request.Builder requestBuilder = createRequestBuilder(header);
//Gibt an, ob der Cache verwendet werden soll
if (!isValidCache) {
requestBuilder.cacheControl(new CacheControl.Builder().noCache().noStore().maxAge(0, TimeUnit.SECONDS).build());
}
//Die Anfrage zusammenstellen
Request request = requestBuilder.url(urlBuilder.build()).build();
//Gibt an, ob der Cache verwendet werden soll
OkHttpClient.Builder clientBuilder = createClientBuilder(isValidCache);
//API-Ausführung
return clientBuilder.build().newCall(request).execute();
}
/**
*Stellen Sie die URL zusammen.
*
* @param type ProtocolType
* @param param parameter
* @return HttpUrl.Builder-Objekt
*/
protected HttpUrl.Builder createUrlBuilder(ProtocolType type, Map<String, String> param) {
//URL Builder
HttpUrl.Builder builder = new HttpUrl.Builder();
//Schema(http or https)
builder.scheme(type.getValue());
//Hostname
builder.host(this.hostname);
//Segment
builder.addPathSegments(this.segment);
if (param != null) {
//Parameter abfragen
param.forEach(builder::addQueryParameter);
}
return builder;
}
/**
*Stellen Sie den HTTP-Header zusammen.
*
* @param param parameter
* @return Request.Builder-Objekt
*/
protected Request.Builder createRequestBuilder(Map<String, String> param) {
Request.Builder builder = new Request.Builder();
builder.addHeader("Content-Type", "application/json");
if (param != null) {
param.forEach(builder::addHeader);
}
return builder;
}
/**
*Stellen Sie den HTTP-Client zusammen.
*
* @param isValidCache Mit oder ohne Cache
* @return OkHttpClient.Builder-Objekt
*/
protected OkHttpClient.Builder createClientBuilder(boolean isValidCache) {
//Gibt an, ob der Cache verwendet werden soll
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (!isValidCache) {
builder.cache(null);
}
return builder;
}
Zertifikat lesen
public class CertificateLoader {
/**
*Lesen Sie das Zertifikat.
*
* @Parameterpfad Zertifikatspfad
* @X509Certificate-Array zurückgeben
*/
public X509Certificate[] load(String path) {
List<X509Certificate> certificateList = new ArrayList<>();
try {
Collection<? extends Certificate> certificates = getCertificates(path);
for (Certificate certificate : certificates) {
X509Certificate x509certificate = (X509Certificate) certificate;
x509certificate.checkValidity(); //Stellen Sie fest, ob das Zertifikat derzeit gültig ist
certificateList.add(x509certificate);
}
} catch (CertificateExpiredException | CertificateNotYetValidException e) {
throw new RuntimeException("____ failed to check valid cer file.", e);
}
return certificateList.toArray(new X509Certificate[certificateList.size()]);
}
/**
*Zertifikatinformationen abrufen.
*
* @Parameterpfad Zertifikatspfad
* @Zertifikatsinformationen zurückgeben
*/
private Collection<? extends Certificate> getCertificates(String path) {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
InputStream in = this.getClass().getClassLoader().getResourceAsStream(path);
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
return certificates;
} catch (CertificateException e) {
throw new RuntimeException("____ failed to get certificates.");
}
}
Zertifikatsverwaltung
public class CertificateManager {
private CertificateLoader loader;
private X509Certificate[] certificates;
private X509TrustManager trustManager;
/**
*Konstrukteur.
*
* @Parameterpfad Zertifikatspfad
*/
public CertificateManager(String path) {
this.loader = new CertificateLoader();
this.certificates = loader.load(path);
//Erstellen Sie einen Zertifikatmanager und stellen Sie sicher, dass es sich um ein vertrauenswürdiges Serverzertifikat handelt
this.trustManager = createTrustManager(certificates);
checkServerTrusted(trustManager, certificates);
}
/**
*Zertifikatinformationen abrufen.
*
* @Zertifikatsinformationen zurückgeben
*/
public X509Certificate[] getCertificates() {
return this.certificates;
}
/**
*Holen Sie sich TrustManager.
*
* @return TrustManager
*/
public X509TrustManager getTrustManager() {
return this.trustManager;
}
/**
*Generieren Sie TrustManager.
*
* @param-Zertifikate Zertifikatinformationen
* @return TrustManager
*/
private X509TrustManager createTrustManager(X509Certificate[] certificates) {
TrustManager[] trustManagers = null;
try {
char[] password = "password".toCharArray();
KeyStore keyStore = newEmptyKeyStore(password);
int index = 0;
for (X509Certificate certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificate);
}
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers : " + Arrays.toString(trustManagers));
}
} catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
throw new RuntimeException("____ failed to create trust manager.", e);
}
return (X509TrustManager) trustManagers[0];
}
/**
*Erstellen Sie ein leeres KeyStore-Objekt.
*
* @param Passwort Passwort
* @Rückgabe des leeren KeyStore-Objekts
*/
private KeyStore newEmptyKeyStore(char[] password) {
KeyStore keyStore = getDefaultKeyStoreInstance();
try {
InputStream in = null;
keyStore.load(in, password);
} catch (NoSuchAlgorithmException | CertificateException | IOException e) {
throw new RuntimeException("____ failed to load from KeyStore.", e);
}
return keyStore;
}
/**
*Ruft das Standard-KeyStore-Objekt ab.
*
* @Standard-KeyStore-Objekt zurückgeben
*/
private KeyStore getDefaultKeyStoreInstance() {
try {
return KeyStore.getInstance(KeyStore.getDefaultType());
} catch (KeyStoreException e) {
throw new RuntimeException("____ failed to get KeyStore default instance.", e);
}
}
/**
*Überprüfen Sie das Zertifikat.
*
* @param trustManager TrustManager
* @param-Zertifikate Zertifikate
*/
private void checkServerTrusted(X509TrustManager trustManager, X509Certificate[] certificates) {
try {
trustManager.checkServerTrusted(certificates, "SHA256withRSA");
} catch (CertificateException e) {
throw new RuntimeException("____ failed to check server trust.", e);
}
}
Die Überprüfung des Hostnamens funktioniert wahrscheinlich, da die Überprüfungsmethode HostnameVerifier nicht implementiert (überschrieben) wird.
das ist alles