[SPRING] Spring RestTemplate을 사용하여 Https Rest Service에 액세스
SPRINGSpring RestTemplate을 사용하여 Https Rest Service에 액세스
누구나 스프링 샘플 템플릿을 사용하여 https로 보호되는 휴식 서비스 URL에 액세스하는 코드 샘플을 제게 제공 할 수 있습니까?
인증서, 사용자 이름 및 암호가 있습니다. 기본 인증은 서버 측에서 사용되며 제공된 인증서, 사용자 이름 및 암호 (필요한 경우)를 사용하여 해당 서버에 연결할 수있는 클라이언트를 만들고 싶습니다.
해결법
-
==============================
1.
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(new FileInputStream(new File(keyStoreFile)), keyStorePassword.toCharArray()); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( new SSLContextBuilder() .loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, keyStorePassword.toCharArray()) .build(), NoopHostnameVerifier.INSTANCE); HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build(); ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory); MyRecord record = restTemplate.getForObject(uri, MyRecord.class); LOG.debug(record.toString());
-
==============================
2.일반적인 아이디어를 줄 수있는 몇 가지 코드가 있습니다.
일반적인 아이디어를 줄 수있는 몇 가지 코드가 있습니다.
인증서를 신뢰하려면 사용자 지정 ClientHttpRequestFactory를 만들어야합니다. 다음과 같이 보입니다.
final ClientHttpRequestFactory clientHttpRequestFactory = new MyCustomClientHttpRequestFactory(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER, serverInfo); restTemplate.setRequestFactory(clientHttpRequestFactory);
이것은 MyCustomClientHttpRequestFactory의 구현입니다.
public class MyCustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory { private final HostnameVerifier hostNameVerifier; private final ServerInfo serverInfo; public MyCustomClientHttpRequestFactory (final HostnameVerifier hostNameVerifier, final ServerInfo serverInfo) { this.hostNameVerifier = hostNameVerifier; this.serverInfo = serverInfo; } @Override protected void prepareConnection(final HttpURLConnection connection, final String httpMethod) throws IOException { if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection) connection).setHostnameVerifier(hostNameVerifier); ((HttpsURLConnection) connection).setSSLSocketFactory(initSSLContext() .getSocketFactory()); } super.prepareConnection(connection, httpMethod); } private SSLContext initSSLContext() { try { System.setProperty("https.protocols", "TLSv1"); // Set ssl trust manager. Verify against our server thumbprint final SSLContext ctx = SSLContext.getInstance("TLSv1"); final SslThumbprintVerifier verifier = new SslThumbprintVerifier(serverInfo); final ThumbprintTrustManager thumbPrintTrustManager = new ThumbprintTrustManager(null, verifier); ctx.init(null, new TrustManager[] { thumbPrintTrustManager }, null); return ctx; } catch (final Exception ex) { LOGGER.error( "An exception was thrown while trying to initialize HTTP security manager.", ex); return null; } }
이 경우 내 serverInfo 객체에는 서버의 지문이 포함되어 있습니다. 얻을 수있는 TrustManager 인터페이스를 구현해야합니다. SslThumbprintVerifier 또는 인증서를 확인하려는 다른 방법 (항상 true를 반환하도록 결정할 수도 있습니다).
org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER 값은 모든 호스트 이름을 허용합니다. 호스트 이름을 확인해야하는 경우, 다르게 구현해야합니다.
사용자와 암호 및 구현 방법에 대해 잘 모르겠습니다. 자주, Authorization이라는 restTemplate에 헤더를 추가해야합니다. 이 값은 Base :
와 같습니다. 사용자 + 암호는 Base64로 인코딩되어야합니다. -
==============================
3.이 메소드는 더 이상 사용되지 않는 클래스 또는 메소드가없는 솔루션입니다. (Java 8 승인)
이 메소드는 더 이상 사용되지 않는 클래스 또는 메소드가없는 솔루션입니다. (Java 8 승인)
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory);
-
==============================
4.여기 내가 비슷한 문제로 끝난 것이다. 아이디어는 @ Avi의 답변과 동일하지만 정적 인 "System.setProperty ("https.protocols ","TLSv1 ");"을 피하기 위해 모든 조정이 시스템에 영향을주지 않습니다. 여기에서 응답에 의해 고무시켰다 http://www.coderanch.com/t/637177/Security/Disabling-handshake-message-Java
여기 내가 비슷한 문제로 끝난 것이다. 아이디어는 @ Avi의 답변과 동일하지만 정적 인 "System.setProperty ("https.protocols ","TLSv1 ");"을 피하기 위해 모든 조정이 시스템에 영향을주지 않습니다. 여기에서 응답에 의해 고무시켰다 http://www.coderanch.com/t/637177/Security/Disabling-handshake-message-Java
public class MyCustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory { @Override protected void prepareConnection(HttpURLConnection connection, String httpMethod) { try { if (!(connection instanceof HttpsURLConnection)) { throw new RuntimeException("An instance of HttpsURLConnection is expected"); } HttpsURLConnection httpsConnection = (HttpsURLConnection) connection; TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory())); httpsConnection.setHostnameVerifier((hostname, session) -> true); super.prepareConnection(httpsConnection, httpMethod); } catch (Exception e) { throw Throwables.propagate(e); } } /** * We need to invoke sslSocket.setEnabledProtocols(new String[] {"SSLv3"}); * see http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html (Java 8 section) */ private static class MyCustomSSLSocketFactory extends SSLSocketFactory { private final SSLSocketFactory delegate; public MyCustomSSLSocketFactory(SSLSocketFactory delegate) { this.delegate = delegate; } @Override public String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public Socket createSocket(final Socket socket, final String host, final int port, final boolean autoClose) throws IOException { final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final String host, final int port) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final InetAddress host, final int port) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress, final int localPort) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort); return overrideProtocol(underlyingSocket); } private Socket overrideProtocol(final Socket socket) { if (!(socket instanceof SSLSocket)) { throw new RuntimeException("An instance of SSLSocket is expected"); } ((SSLSocket) socket).setEnabledProtocols(new String[] {"SSLv3"}); return socket; } } }
-
==============================
5.나 한테서 요. 나는 스프링 부트 마이크로 서비스와 상호 인증서 인증을 사용했다. 다음은 나를 위해 일하고있다, 열쇠는 여기에있다. keyManagerFactory.init (...) 및 sslcontext.init (keyManagerFactory.getKeyManagers (), null, 새로운 SecureRandom ()) 코드를 사용하지 않고도 최소한의 작업만으로는 작동하지 않았습니다. 인증서는 PKCS12에 의해 패키지됩니다.
나 한테서 요. 나는 스프링 부트 마이크로 서비스와 상호 인증서 인증을 사용했다. 다음은 나를 위해 일하고있다, 열쇠는 여기에있다. keyManagerFactory.init (...) 및 sslcontext.init (keyManagerFactory.getKeyManagers (), null, 새로운 SecureRandom ()) 코드를 사용하지 않고도 최소한의 작업만으로는 작동하지 않았습니다. 인증서는 PKCS12에 의해 패키지됩니다.
@Value("${server.ssl.key-store-password}") private String keyStorePassword; @Value("${server.ssl.key-store-type}") private String keyStoreType; @Value("${server.ssl.key-store}") private Resource resource; private RestTemplate getRestTemplate() throws Exception { return new RestTemplate(clientHttpRequestFactory()); } private ClientHttpRequestFactory clientHttpRequestFactory() throws Exception { return new HttpComponentsClientHttpRequestFactory(httpClient()); } private HttpClient httpClient() throws Exception { KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); KeyStore trustStore = KeyStore.getInstance(keyStoreType); if (resource.exists()) { InputStream inputStream = resource.getInputStream(); try { if (inputStream != null) { trustStore.load(inputStream, keyStorePassword.toCharArray()); keyManagerFactory.init(trustStore, keyStorePassword.toCharArray()); } } finally { if (inputStream != null) { inputStream.close(); } } } else { throw new RuntimeException("Cannot find resource: " + resource.getFilename()); } SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build(); sslcontext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom()); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1.2"}, null, getDefaultHostnameVerifier()); return HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build(); }
from https://stackoverflow.com/questions/17619871/access-https-rest-service-using-spring-resttemplate by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring Security @ PreAuthorize / @ PostAuthorize 어노테이션에서 커스텀 표현식을 사용하는 방법 (0) | 2018.12.29 |
---|---|
[SPRING] 세션에서 Spring 저장 객체 (0) | 2018.12.29 |
[SPRING] Spring 3.0 대 Java EE 6.0 [닫기] (0) | 2018.12.29 |
[SPRING] Spring MVC 컨트롤러 메서드에서 GET HTTP 요청의 매개 변수 값을 얻는 방법은 무엇입니까? (0) | 2018.12.29 |
[SPRING] 스프링 설정 디버깅 (0) | 2018.12.29 |