设为首页 收藏本站
查看: 552|回复: 0

[经验分享] Apache Mina

[复制链接]

尚未签到

发表于 2016-12-31 09:46:37 | 显示全部楼层 |阅读模式
本文中我们看一下如何为一个简单的客户端/服务器应用程序配置安全套接字(SSL)。 我们需要一下3个步骤:


创建SSLContext

服务器部分

客户端部分

第一步 – 创建SSLContext


SSLContext是用来创建SSLSocket或SSLEngine的。在下面的例子中有一个类SSLContextGenerator用来创建SSLContext。要进行加密的传输,我们还需要两个密钥文件:keystore和truststore。要创建这两个文件可以参见“用keytool创建Keystore和Trustsotre文件”。在SSLContextGenerator里我们使用了下面两个工厂类:



KeyStoreFactory - 创建和配置KeyStore实例的工厂类。

SSLContextFactory - 创建和配置SSLContext实例。



SSLContextGenerator.java

Java代码 DSC0000.gif





  • packagecom.sample.ssl;


  • importjava.io.File;

  • importjava.security.KeyStore;

  • importjavax.net.ssl.SSLContext;

  • importorg.apache.mina.filter.ssl.KeyStoreFactory;

  • importorg.apache.mina.filter.ssl.SslContextFactory;


  • publicclassSSLContextGenerator
  • {

  • publicSSLContextgetSslContext()
  • {

  • SSLContextsslContext=null;

  • try
  • {

  • FilekeyStoreFile=newFile("/home/giftsam/Desktop/certificates/keystore");

  • FiletrustStoreFile=newFile("/home/giftsam/Desktop/certificates/truststore");


  • if(keyStoreFile.exists()&&trustStoreFile.exists()){

  • finalKeyStoreFactorykeyStoreFactory=newKeyStoreFactory();

  • System.out.println("Urlis:"+keyStoreFile.getAbsolutePath());
  • keyStoreFactory.setDataFile(keyStoreFile);

  • keyStoreFactory.setPassword("techbrainwave");


  • finalKeyStoreFactorytrustStoreFactory=newKeyStoreFactory();
  • trustStoreFactory.setDataFile(trustStoreFile);

  • trustStoreFactory.setPassword("techbrainwave");


  • finalSslContextFactorysslContextFactory=newSslContextFactory();

  • finalKeyStorekeyStore=keyStoreFactory.newInstance();
  • sslContextFactory.setKeyManagerFactoryKeyStore(keyStore);


  • finalKeyStoretrustStore=trustStoreFactory.newInstance();
  • sslContextFactory.setTrustManagerFactoryKeyStore(trustStore);

  • sslContextFactory.setKeyManagerFactoryKeyStorePassword("techbrainwave");
  • sslContext=sslContextFactory.newInstance();

  • System.out.println("SSLprovideris:"+sslContext.getProvider());

  • }else{

  • System.out.println("KeystoreorTruststorefiledoesnotexist");
  • }

  • }catch(Exceptionex){
  • ex.printStackTrace();
  • }

  • returnsslContext;
  • }
  • }



package com.sample.ssl;
import java.io.File;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import org.apache.mina.filter.ssl.KeyStoreFactory;
import org.apache.mina.filter.ssl.SslContextFactory;
public class SSLContextGenerator
{
public SSLContext getSslContext()
{
SSLContext sslContext = null;
try
{
File keyStoreFile = new File("/home/giftsam/Desktop/certificates/keystore");
File trustStoreFile = new File("/home/giftsam/Desktop/certificates/truststore");
if (keyStoreFile.exists() && trustStoreFile.exists()) {
final KeyStoreFactory keyStoreFactory = new KeyStoreFactory();
System.out.println("Url is: " + keyStoreFile.getAbsolutePath());
keyStoreFactory.setDataFile(keyStoreFile);
keyStoreFactory.setPassword("techbrainwave");
final KeyStoreFactory trustStoreFactory = new KeyStoreFactory();
trustStoreFactory.setDataFile(trustStoreFile);
trustStoreFactory.setPassword("techbrainwave");
final SslContextFactory sslContextFactory = new SslContextFactory();
final KeyStore keyStore = keyStoreFactory.newInstance();
sslContextFactory.setKeyManagerFactoryKeyStore(keyStore);
final KeyStore trustStore = trustStoreFactory.newInstance();
sslContextFactory.setTrustManagerFactoryKeyStore(trustStore);
sslContextFactory.setKeyManagerFactoryKeyStorePassword("techbrainwave");
sslContext = sslContextFactory.newInstance();
System.out.println("SSL provider is: " + sslContext.getProvider());
} else {
System.out.println("Keystore or Truststore file does not exist");
}
} catch (Exception ex) {
ex.printStackTrace();
}
return sslContext;
}
}



第二步 - 服务器部分


服务器部分有两个类,SSLServer 和 SSLServerHandler。 SSLServer类里,我们用MINA的SSLFilter来加密和解密传输的数据。同时这个类会立即触发SSL的Handshake的处理(如果你不想立即触发handshake处理,可以指定构造函数的autostart参数为false)。



注意:SSLFilter只用在TCP/IP的连接。


IoAcceptor接口用来接受客户端过来的连接请求,触发IoHandler中的事件。在本例中使用了两个Filter,LoggingFilter用来记录所有的事件和请求。 第二个是ProtocolCodecFilter用来把进来的ByteBuffer转换成POJO的消息对象。SSLFilter要放在过滤器链的最前端,以保证后面的Filter里利用到的数据是已经解密过的。



SSLServer.java


Java代码




  • packagecom.sample.ssl;


  • importjava.io.IOException;

  • importjava.net.InetSocketAddress;

  • importjava.nio.charset.Charset;

  • importjava.security.GeneralSecurityException;

  • importorg.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;


  • importorg.apache.mina.core.session.IdleStatus;

  • importorg.apache.mina.core.service.IoAcceptor;

  • importorg.apache.mina.filter.codec.ProtocolCodecFilter;

  • importorg.apache.mina.filter.codec.textline.TextLineCodecFactory;

  • importorg.apache.mina.filter.logging.LoggingFilter;

  • importorg.apache.mina.filter.ssl.SslFilter;

  • importorg.apache.mina.transport.socket.nio.NioSocketAcceptor;


  • publicclassSSLServer
  • {

  • privatestaticfinalintPORT=5000;



  • privatestaticvoidaddSSLSupport(DefaultIoFilterChainBuilderchain)
  • {

  • try
  • {

  • SslFiltersslFilter=newSslFilter(newSSLContextGenerator().getSslContext());

  • chain.addLast("sslFilter",sslFilter);

  • System.out.println("SSLsupportisadded..");
  • }

  • catch(Exceptionex)
  • {
  • ex.printStackTrace();
  • }
  • }


  • publicstaticvoidmain(String[]args)throwsIOException,GeneralSecurityException

  • {

  • IoAcceptoracceptor=newNioSocketAcceptor();
  • DefaultIoFilterChainBuilderchain=acceptor.getFilterChain();

  • addSSLSupport(chain);


  • chain.addLast("logger",newLoggingFilter());

  • chain.addLast("codec",newProtocolCodecFilter(newTextLineCodecFactory(Charset.forName("UTF-8"))));



  • acceptor.setHandler(newSSLServerHandler());

  • acceptor.getSessionConfig().setReadBufferSize(2048);

  • acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE,10);

  • acceptor.bind(newInetSocketAddress(PORT));

  • System.out.println("ServerStarted..");
  • }
  • }



package com.sample.ssl;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filter.ssl.SslFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class SSLServer
{
private static final int PORT = 5000;
private static void addSSLSupport(DefaultIoFilterChainBuilder chain)
{
try
{
SslFilter sslFilter = new SslFilter(new SSLContextGenerator().getSslContext());
chain.addLast("sslFilter", sslFilter);
System.out.println("SSL support is added..");
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
public static void main(String[] args) throws IOException, GeneralSecurityException
{
IoAcceptor acceptor = new NioSocketAcceptor();
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
addSSLSupport(chain);
chain.addLast("logger", new LoggingFilter());
chain.addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
acceptor.setHandler(new SSLServerHandler());
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("Server Started..");
}
}




SSLServerHandler类有4个方法。sessionOpened在会话打开是被调用,可以在这个方法里进行会话的初始配置如会话空闲时间。messageReceived方法在接收到客户端发来的消息后被调用。会话闲置10秒后会调用sessionIdle方法,我们在这里把会话结束掉。当异常发生后messageReceived方法会被调用,我们在这个方法里关闭会话。



SSLServerHandler.java



Java代码




  • packagecom.sample.ssl;


  • importorg.apache.mina.core.session.IdleStatus;

  • importorg.apache.mina.core.service.IoHandlerAdapter;

  • importorg.apache.mina.core.session.IoSession;

  • importorg.slf4j.Logger;

  • importorg.slf4j.LoggerFactory;


  • publicclassSSLServerHandlerextendsIoHandlerAdapter
  • {

  • privatefinalLoggerlogger=(Logger)LoggerFactory.getLogger(getClass());

  • privateintidleTimeout=10;


  • @Override

  • publicvoidsessionOpened(IoSessionsession)
  • {

  • //设置会话闲置为10秒
  • session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE,idleTimeout);

  • session.setAttribute("Values:");
  • }


  • @Override

  • publicvoidmessageReceived(IoSessionsession,Objectmessage)
  • {

  • System.out.println("Messagereceivedintheserver..");

  • System.out.println("Messageis:"+message.toString());
  • }


  • @Override

  • publicvoidsessionIdle(IoSessionsession,IdleStatusstatus)
  • {

  • logger.info("Transactionisidlefor"+idleTimeout+"secs,Sodisconnecting..");

  • //把空闲的会话关闭
  • session.close();
  • }


  • @Override

  • publicvoidexceptionCaught(IoSessionsession,Throwablecause)
  • {

  • //出现异常是也关闭连接
  • session.close();
  • }
  • }



package com.sample.ssl;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SSLServerHandler extends IoHandlerAdapter
{
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
private int idleTimeout = 10;
@Override
public void sessionOpened(IoSession session)
{
// 设置会话闲置为10秒
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, idleTimeout);
session.setAttribute("Values: ");
}
@Override
public void messageReceived(IoSession session, Object message)
{
System.out.println("Message received in the server..");
System.out.println("Message is: " + message.toString());
}
@Override
public void sessionIdle(IoSession session, IdleStatus status)
{
logger.info("Transaction is idle for " + idleTimeout + "secs, So disconnecting..");
// 把空闲的会话关闭
session.close();
}
@Override
public void exceptionCaught(IoSession session, Throwable cause)
{
// 出现异常是也关闭连接
session.close();
}
}


第三步 - 客户端部分


客户端部分有两个类SSLClient和SSLClientHandler。在SSLClient类里,我们同样适用SSLFilter来加密和解密传输的数据。 SSLFilter的UseClientMode属性被设置为True,标识这个SSLFilter在做handshake时是客户端模式。



IoConnector用来和服务器通信并且触发IoHandler中的事件。和服务器端一样,我们使用了LoggingFilter和ProtocolCodecFilter。 ConnectFuture用来实现异步的连接请求。



Java代码




  • packagecom.sample.ssl;


  • importjava.io.IOException;

  • importjava.net.InetSocketAddress;

  • importjava.nio.charset.Charset;

  • importjava.security.GeneralSecurityException;

  • importjavax.net.ssl.SSLContext;

  • importorg.apache.mina.core.future.ConnectFuture;

  • importorg.apache.mina.core.service.IoConnector;

  • importorg.apache.mina.core.session.IoSession;

  • importorg.apache.mina.filter.codec.ProtocolCodecFilter;

  • importorg.apache.mina.filter.codec.textline.TextLineCodecFactory;

  • importorg.apache.mina.filter.logging.LoggingFilter;

  • importorg.apache.mina.filter.ssl.SslFilter;

  • importorg.apache.mina.transport.socket.nio.NioSocketConnector;


  • publicclassSSLClient
  • {

  • privatestaticfinalintREMORT_PORT=5000;



  • publicstaticvoidmain(String[]args)throwsIOException,InterruptedException,GeneralSecurityException

  • {

  • IoConnectorconnector=newNioSocketConnector();

  • connector.getSessionConfig().setReadBufferSize(2048);


  • SSLContextsslContext=newSSLContextGenerator().getSslContext();

  • System.out.println("SSLContextprotocolis:"+sslContext.getProtocol());


  • SslFiltersslFilter=newSslFilter(sslContext);

  • sslFilter.setUseClientMode(true);

  • connector.getFilterChain().addFirst("sslFilter",sslFilter);


  • connector.getFilterChain().addLast("logger",newLoggingFilter());

  • connector.getFilterChain().addLast("codec",newProtocolCodecFilter(newTextLineCodecFactory(Charset.forName("UTF-8"))));



  • connector.setHandler(newSSLClientHandler("HelloServer.."));

  • ConnectFuturefuture=connector.connect(newInetSocketAddress("172.108.0.6",REMORT_PORT));
  • future.awaitUninterruptibly();


  • if(!future.isConnected())
  • {

  • return;
  • }
  • IoSessionsession=future.getSession();

  • session.getConfig().setUseReadOperation(true);
  • session.getCloseFuture().awaitUninterruptibly();

  • System.out.println("AfterWriting");
  • connector.dispose();
  • }
  • }



package com.sample.ssl;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import javax.net.ssl.SSLContext;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filter.ssl.SslFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
public class SSLClient
{
private static final int REMORT_PORT = 5000;
public static void main(String[] args) throws IOException, InterruptedException, GeneralSecurityException
{
IoConnector connector = new NioSocketConnector();
connector.getSessionConfig().setReadBufferSize(2048);
SSLContext sslContext = new SSLContextGenerator().getSslContext();
System.out.println("SSLContext protocol is: " + sslContext.getProtocol());
SslFilter sslFilter = new SslFilter(sslContext);
sslFilter.setUseClientMode(true);
connector.getFilterChain().addFirst("sslFilter", sslFilter);
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
connector.setHandler(new SSLClientHandler("Hello Server.."));
ConnectFuture future = connector.connect(new InetSocketAddress("172.108.0.6", REMORT_PORT));
future.awaitUninterruptibly();
if (!future.isConnected())
{
return;
}
IoSession session = future.getSession();
session.getConfig().setUseReadOperation(true);
session.getCloseFuture().awaitUninterruptibly();
System.out.println("After Writing");
connector.dispose();
}
}



IoHandler部分,和服务端一样有“sessionOpened”, “messageReceived” 和 “exceptionCaught”方法。


SSLClientHandler.java


Java代码




  • packagecom.sample.ssl;


  • importorg.apache.mina.core.service.IoHandlerAdapter;

  • importorg.apache.mina.core.session.IoSession;

  • importorg.slf4j.Logger;

  • importorg.slf4j.LoggerFactory;


  • publicclassSSLClientHandlerextendsIoHandlerAdapter
  • {

  • privatefinalLoggerlogger=(Logger)LoggerFactory.getLogger(getClass());

  • privatefinalStringvalues;

  • privatebooleanfinished;


  • publicSSLClientHandler(Stringvalues)
  • {

  • this.values=values;
  • }


  • publicbooleanisFinished()
  • {

  • returnfinished;
  • }


  • @Override

  • publicvoidsessionOpened(IoSessionsession)
  • {
  • session.write(values);
  • }


  • @Override

  • publicvoidmessageReceived(IoSessionsession,Objectmessage)
  • {

  • logger.info("Messagereceivedintheclient..");

  • logger.info("Messageis:"+message.toString());
  • }


  • @Override

  • publicvoidexceptionCaught(IoSessionsession,Throwablecause)
  • {
  • session.close();
  • }
  • }



package com.sample.ssl;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SSLClientHandler extends IoHandlerAdapter
{
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
private final String values;
private boolean finished;
public SSLClientHandler(String values)
{
this.values = values;
}
public boolean isFinished()
{
return finished;
}
@Override
public void sessionOpened(IoSession session)
{
session.write(values);
}
@Override
public void messageReceived(IoSession session, Object message)
{
logger.info("Message received in the client..");
logger.info("Message is: " + message.toString());
}
@Override
public void exceptionCaught(IoSession session, Throwable cause)
{
session.close();
}
}



现在我们来测试一下上面的代码。 先执行SSLServer,然后执行SSLClient。就可以看到在控制台里可以输出了一下内容:


服务端输出


Text代码




  • Urlis:/home/giftsam/Desktop/certificates/keystore

  • SSLProvideris:SunJSSEversion1.6
  • SSLsupportisadded..
  • ServerStarted..

  • Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog

  • INFO:CREATED

  • Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog

  • INFO:OPENED

  • Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog


  • INFO:RECEIVED:HeapBuffer[pos=0lim=15cap=36:48656C6C6F205365727665722E2E0A]

  • Messagereceivedintheserver..
  • Messageis:HelloServer..

  • Dec10,20108:38:09PMorg.apache.mina.filter.logging.LoggingFilterlog

  • INFO:IDLE

  • Dec10,20108:38:09PMcom.sample.ssl.SSLServerHandlersessionIdle

  • INFO:Transactionisidlefor10secs,Sodisconnecting..

  • Dec10,20108:38:09PMorg.apache.mina.filter.logging.LoggingFilterlog

  • INFO:CLOSED



Url is: /home/giftsam/Desktop/certificates/keystore
SSL Provider is: SunJSSE version 1.6
SSL support is added..
Server Started..
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: CREATED
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: OPENED
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: RECEIVED: HeapBuffer[pos=0 lim=15 cap=36: 48 65 6C 6C 6F 20 53 65 72 76 65 72 2E 2E 0A]
Message received in the server..
Message is: Hello Server..
Dec 10, 2010 8:38:09 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: IDLE
Dec 10, 2010 8:38:09 PM com.sample.ssl.SSLServerHandler sessionIdle
INFO: Transaction is idle for 10secs, So disconnecting..
Dec 10, 2010 8:38:09 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: CLOSED



客户端输出


Text代码




  • Urlis:/home/giftsam/Desktop/certificates/keystore

  • SSLProvideris:SunJSSEversion1.6
  • SSLContextprotocolis:TLS

  • Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog

  • INFO:CREATED

  • Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog

  • INFO:OPENED

  • Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog


  • INFO:SENT:HeapBuffer[pos=0lim=15cap=16:48656C6C6F205365727665722E2E0A]


  • Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog


  • INFO:SENT:HeapBuffer[pos=0lim=0cap=0:empty]

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-321880-1-1.html 上篇帖子: Apache 多个tomcat 多域名 下篇帖子: Apache POI操作Word概览
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表