您的位置:首页 > 理论基础 > 计算机网络

HttpInvoker SSL双向认证远程接口调用

2014-04-02 14:18 295 查看
在工作中,遇到需要开放一个web接口给对方调用,所以用到了HttpInvoker ,但是又遇到了一个问题,就是采用的是双向认证,只开放443端口,也就是说配置接口必须采用https,而且调用接口时,还需要通过双向认证。下面是我做的事例,贴出来供大家参考。

一、创建接口和接口实现类

public interface SyncRemoteService {

/**

* 挂网成功后需要更新数据列表

*

* @return List<List<String>>

*/

public void syncBackDatas(List<List<String>> syncDatas);

/**

* 挂网成功后需要更新数据内容

*

* @param json 字符串

*/

public void syncBackData(String json);

}

二、HttpInvoker 服务端配置

applicationContext.xml

<!-- 挂网返回结果接口 -->

<bean id ="syncRemoteService" class = "com.noah.nrmp.resource.file.service.impl.SyncRemoteServiceImpl" />

<bean name ="syncRemoteServiceExporter" class = "org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter" >

<property name = "service" ref = "syncRemoteService" />

<property name = "serviceInterface" value = "com.noah.nrmp.resource.file.service.SyncRemoteService" />

</bean>

web.xml 文件配置

<servlet>

<servlet-name>syncRemoteServiceExporter</servlet-name>

<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>syncRemoteServiceExporter</servlet-name>

<url-pattern>/SyncRemoteService</url-pattern>

</servlet-mapping>

二、HttpInvoker 客户端配置

需要commons-httpclient-3.1.jar包,还需要什么依赖包,自己查下资料吧

applicationContext.xml

<bean id="syncRemoteService"

class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">

<property name="serviceUrl"

value="https://www.nrmp2.anoah/NRMP_TEST/SyncRemoteService" />

<property name="serviceInterface" value="com.noah.nrmp.resource.file.service.SyncRemoteService" />

<property name="httpInvokerRequestExecutor">

<bean class="com.noah.nrmp.resource.file.service.SSLCommonsHttpInvokerRequestExecutor"/>

</property>

</bean>

因为这里需要双向认证,所以我自己实现了CommonsHttpInvokerRequestExecutor,方便加入SSL证书

SSLCommonsHttpInvokerRequestExecutor 内容如下:

public class SSLCommonsHttpInvokerRequestExecutor extends CommonsHttpInvokerRequestExecutor {

private HttpClient httpClient;

@SuppressWarnings("deprecation")

public SSLCommonsHttpInvokerRequestExecutor(){

Protocol.registerProtocol("https", new Protocol("https", new SimpleSSLTestProtocolSocketFactory(),443));

this.httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());

}

public SSLCommonsHttpInvokerRequestExecutor(HttpClient httpClient) {

this.httpClient = httpClient;

}

@Override

public void setHttpClient(HttpClient httpClient) {

this.httpClient = httpClient;

}

@Override

public HttpClient getHttpClient() {

return httpClient;

}

}

关键是加入这句话:Protocol.registerProtocol("https", new Protocol("https", new SimpleSSLTestProtocolSocketFactory(),443));

在SimpleSSLTestProtocolSocketFactory中加载客户端证书和服务端证书

SimpleSSLTestProtocolSocketFactory 内容如下:

public class SimpleSSLTestProtocolSocketFactory implements SecureProtocolSocketFactory {

private static final Log LOG = LogFactory.getLog(SimpleSSLTestProtocolSocketFactory.class);

private static SSLContext SSLCONTEXT = null;

private static SSLContext createSSLContext() {

try {

KeyStore keystore = KeyStore.getInstance("PKCS12");

FileInputStream ksInstream = new FileInputStream(new File("D:\\client.p12"));

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());

FileInputStream trustInstream = new FileInputStream(new File("D:\\jssecacerts"));

try {

keystore.load(ksInstream, "test".toCharArray());

trustStore.load(trustInstream, "change".toCharArray());

} finally {

if (ksInstream != null)

ksInstream.close();

if (trustInstream!=null)

trustInstream.close();

}

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

keyManagerFactory.init(keystore, "test".toCharArray());

trustManagerFactory.init(trustStore);

KeyManager[] keymanagers=keyManagerFactory.getKeyManagers();

TrustManager[] trustmanagers = trustManagerFactory.getTrustManagers();

SSLContext sslcontext = SSLContext.getInstance("TLS");

sslcontext.init(keymanagers, trustmanagers, null);

return sslcontext;

} catch (Exception ex) {

LOG.error(ex.getMessage(), ex);

throw new IllegalStateException(ex.getMessage());

}

}

private static SSLContext getSSLContext() {

if (SSLCONTEXT == null) {

SSLCONTEXT = createSSLContext();

}

return SSLCONTEXT;

}

public SimpleSSLTestProtocolSocketFactory() {

super();

}

public Socket createSocket(final String host, final int port,

final InetAddress localAddress, final int localPort,

final HttpConnectionParams params) throws IOException,

UnknownHostException, ConnectTimeoutException {

if (params == null) {

throw new IllegalArgumentException("Parameters may not be null");

}

int timeout = params.getConnectionTimeout();

if (timeout == 0) {

return createSocket(host, port, localAddress, localPort);

} else {

// To be eventually deprecated when migrated to Java 1.4 or above

return ControllerThreadSocketFactory.createSocket(this, host, port,

localAddress, localPort, timeout);

}

}

public Socket createSocket(String host, int port, InetAddress clientHost,

int clientPort) throws IOException, UnknownHostException {

return getSSLContext().getSocketFactory().createSocket(host, port,

clientHost, clientPort);

}

public Socket createSocket(String host, int port) throws IOException,

UnknownHostException {

return getSSLContext().getSocketFactory().createSocket(host, port);

}

public Socket createSocket(Socket socket, String host, int port,

boolean autoClose) throws IOException, UnknownHostException {

return getSSLContext().getSocketFactory().createSocket(socket, host,

port, autoClose);

}

}

其中 keystore.load(ksInstream, "test".toCharArray());

trustStore.load(trustInstream, "changeit".toCharArray());

test 和changeit为证书密码

FileInputStream trustInstream = new FileInputStream(new File("D:\\jssecacerts"));

jssecacerts 文件生成代码 如下:

public class InstallCert {

public static void main(String[] args) throws Exception {

String host;

int port;

char[] passphrase;

if ((args.length == 1) || (args.length == 2)) {

String[] c = args[0].split(":");

host = c[0];

port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);

String p = (args.length == 1) ? "changeit" : args[1];

passphrase = p.toCharArray();

} else {

System.out.println("Usage: java InstallCert <host>[:port] [passphrase]");

return;

}

File file = new File("jssecacerts");

if (file.isFile() == false) {

char SEP = File.separatorChar;

File dir = new File(System.getProperty("java.home") + SEP

+ "lib" + SEP + "security");

file = new File(dir, "jssecacerts");

if (file.isFile() == false) {

file = new File(dir, "cacerts");

}

}

System.out.println("Loading KeyStore " + file + "...");

InputStream in = new FileInputStream(file);

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

ks.load(in, passphrase);

in.close();

SSLContext context = SSLContext.getInstance("TLS");

TrustManagerFactory tmf =

TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

tmf.init(ks);

X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];

SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);

context.init(null, new TrustManager[]{tm}, null);

SSLSocketFactory factory = context.getSocketFactory();

System.out.println("Opening connection to " + host + ":" + port + "...");

SSLSocket socket = (SSLSocket) factory.createSocket(host, port);

socket.setSoTimeout(10000);

try {

System.out.println("Starting SSL handshake...");

socket.startHandshake();

socket.close();

System.out.println();

System.out.println("No errors, certificate is already trusted");

} catch (SSLException e) {

System.out.println();

e.printStackTrace(System.out);

}

X509Certificate[] chain = tm.chain;

if (chain == null) {

System.out.println("Could not obtain server certificate chain");

return;

}

BufferedReader reader =

new BufferedReader(new InputStreamReader(System.in));

System.out.println();

System.out.println("Server sent " + chain.length + " certificate(s):");

System.out.println();

MessageDigest sha1 = MessageDigest.getInstance("SHA1");

MessageDigest md5 = MessageDigest.getInstance("MD5");

for (int i = 0; i < chain.length; i++) {

X509Certificate cert = chain[i];

System.out.println

(" " + (i + 1) + " Subject " + cert.getSubjectDN());

System.out.println(" Issuer " + cert.getIssuerDN());

sha1.update(cert.getEncoded());

System.out.println(" sha1 " + toHexString(sha1.digest()));

md5.update(cert.getEncoded());

System.out.println(" md5 " + toHexString(md5.digest()));

System.out.println();

}

System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");

String line = reader.readLine().trim();

int k;

try {

k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;

} catch (NumberFormatException e) {

System.out.println("KeyStore not changed");

return;

}

X509Certificate cert = chain[k];

String alias = host + "-" + (k + 1);

ks.setCertificateEntry(alias, cert);

OutputStream out = new FileOutputStream("jssecacerts");

ks.store(out, passphrase);

out.close();

System.out.println();

System.out.println(cert);

System.out.println();

System.out.println

("Added certificate to keystore 'jssecacerts' using alias '"

+ alias + "'");

}

private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();

private static String toHexString(byte[] bytes) {

StringBuilder sb = new StringBuilder(bytes.length * 3);

for (int b : bytes) {

b &= 0xff;

sb.append(HEXDIGITS[b >> 4]);

sb.append(HEXDIGITS[b & 15]);

sb.append(' ');

}

return sb.toString();

}

private static class SavingTrustManager implements X509TrustManager {

private final X509TrustManager tm;

private X509Certificate[] chain;

SavingTrustManager(X509TrustManager tm) {

this.tm = tm;

}

public X509Certificate[] getAcceptedIssuers() {

throw new UnsupportedOperationException();

}

public void checkClientTrusted(X509Certificate[] chain, String authType)

throws CertificateException {

throw new UnsupportedOperationException();

}

public void checkServerTrusted(X509Certificate[] chain, String authType)

throws CertificateException {

this.chain = chain;

tm.checkServerTrusted(chain, authType);

}

}

}

好了,大致就这样,就能实现HttpInvoker 双向认证 接口调用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: