Apache Mina - SSL配置

本文介绍如何为客户端/服务器应用配置SSL,包括创建SSLContext、服务器端和客户端的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文中我们看一下如何为一个简单的客户端/服务器应用程序配置安全套接字(SSL)。 我们需要一下3个步骤:

创建SSLContext
服务器部分
客户端部分

第一步 – 创建SSLContext

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

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


SSLContextGenerator.java
Java代码 复制代码
  1. packagecom.sample.ssl;
  2. importjava.io.File;
  3. importjava.security.KeyStore;
  4. importjavax.net.ssl.SSLContext;
  5. importorg.apache.mina.filter.ssl.KeyStoreFactory;
  6. importorg.apache.mina.filter.ssl.SslContextFactory;
  7. publicclassSSLContextGenerator
  8. {
  9. publicSSLContextgetSslContext()
  10. {
  11. SSLContextsslContext=null;
  12. try
  13. {
  14. FilekeyStoreFile=newFile("/home/giftsam/Desktop/certificates/keystore");
  15. FiletrustStoreFile=newFile("/home/giftsam/Desktop/certificates/truststore");
  16. if(keyStoreFile.exists()&&trustStoreFile.exists()){
  17. finalKeyStoreFactorykeyStoreFactory=newKeyStoreFactory();
  18. System.out.println("Urlis:"+keyStoreFile.getAbsolutePath());
  19. keyStoreFactory.setDataFile(keyStoreFile);
  20. keyStoreFactory.setPassword("techbrainwave");
  21. finalKeyStoreFactorytrustStoreFactory=newKeyStoreFactory();
  22. trustStoreFactory.setDataFile(trustStoreFile);
  23. trustStoreFactory.setPassword("techbrainwave");
  24. finalSslContextFactorysslContextFactory=newSslContextFactory();
  25. finalKeyStorekeyStore=keyStoreFactory.newInstance();
  26. sslContextFactory.setKeyManagerFactoryKeyStore(keyStore);
  27. finalKeyStoretrustStore=trustStoreFactory.newInstance();
  28. sslContextFactory.setTrustManagerFactoryKeyStore(trustStore);
  29. sslContextFactory.setKeyManagerFactoryKeyStorePassword("techbrainwave");
  30. sslContext=sslContextFactory.newInstance();
  31. System.out.println("SSLprovideris:"+sslContext.getProvider());
  32. }else{
  33. System.out.println("KeystoreorTruststorefiledoesnotexist");
  34. }
  35. }catch(Exceptionex){
  36. ex.printStackTrace();
  37. }
  38. returnsslContext;
  39. }
  40. }
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代码
  1. packagecom.sample.ssl;
  2. importjava.io.IOException;
  3. importjava.net.InetSocketAddress;
  4. importjava.nio.charset.Charset;
  5. importjava.security.GeneralSecurityException;
  6. importorg.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
  7. importorg.apache.mina.core.session.IdleStatus;
  8. importorg.apache.mina.core.service.IoAcceptor;
  9. importorg.apache.mina.filter.codec.ProtocolCodecFilter;
  10. importorg.apache.mina.filter.codec.textline.TextLineCodecFactory;
  11. importorg.apache.mina.filter.logging.LoggingFilter;
  12. importorg.apache.mina.filter.ssl.SslFilter;
  13. importorg.apache.mina.transport.socket.nio.NioSocketAcceptor;
  14. publicclassSSLServer
  15. {
  16. privatestaticfinalintPORT=5000;
  17. privatestaticvoidaddSSLSupport(DefaultIoFilterChainBuilderchain)
  18. {
  19. try
  20. {
  21. SslFiltersslFilter=newSslFilter(newSSLContextGenerator().getSslContext());
  22. chain.addLast("sslFilter",sslFilter);
  23. System.out.println("SSLsupportisadded..");
  24. }
  25. catch(Exceptionex)
  26. {
  27. ex.printStackTrace();
  28. }
  29. }
  30. publicstaticvoidmain(String[]args)throwsIOException,GeneralSecurityException
  31. {
  32. IoAcceptoracceptor=newNioSocketAcceptor();
  33. DefaultIoFilterChainBuilderchain=acceptor.getFilterChain();
  34. addSSLSupport(chain);
  35. chain.addLast("logger",newLoggingFilter());
  36. chain.addLast("codec",newProtocolCodecFilter(newTextLineCodecFactory(Charset.forName("UTF-8"))));
  37. acceptor.setHandler(newSSLServerHandler());
  38. acceptor.getSessionConfig().setReadBufferSize(2048);
  39. acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE,10);
  40. acceptor.bind(newInetSocketAddress(PORT));
  41. System.out.println("ServerStarted..");
  42. }
  43. }
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代码
  1. packagecom.sample.ssl;
  2. importorg.apache.mina.core.session.IdleStatus;
  3. importorg.apache.mina.core.service.IoHandlerAdapter;
  4. importorg.apache.mina.core.session.IoSession;
  5. importorg.slf4j.Logger;
  6. importorg.slf4j.LoggerFactory;
  7. publicclassSSLServerHandlerextendsIoHandlerAdapter
  8. {
  9. privatefinalLoggerlogger=(Logger)LoggerFactory.getLogger(getClass());
  10. privateintidleTimeout=10;
  11. @Override
  12. publicvoidsessionOpened(IoSessionsession)
  13. {
  14. //设置会话闲置为10秒
  15. session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE,idleTimeout);
  16. session.setAttribute("Values:");
  17. }
  18. @Override
  19. publicvoidmessageReceived(IoSessionsession,Objectmessage)
  20. {
  21. System.out.println("Messagereceivedintheserver..");
  22. System.out.println("Messageis:"+message.toString());
  23. }
  24. @Override
  25. publicvoidsessionIdle(IoSessionsession,IdleStatusstatus)
  26. {
  27. logger.info("Transactionisidlefor"+idleTimeout+"secs,Sodisconnecting..");
  28. //把空闲的会话关闭
  29. session.close();
  30. }
  31. @Override
  32. publicvoidexceptionCaught(IoSessionsession,Throwablecause)
  33. {
  34. //出现异常是也关闭连接
  35. session.close();
  36. }
  37. }
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代码
  1. packagecom.sample.ssl;
  2. importjava.io.IOException;
  3. importjava.net.InetSocketAddress;
  4. importjava.nio.charset.Charset;
  5. importjava.security.GeneralSecurityException;
  6. importjavax.net.ssl.SSLContext;
  7. importorg.apache.mina.core.future.ConnectFuture;
  8. importorg.apache.mina.core.service.IoConnector;
  9. importorg.apache.mina.core.session.IoSession;
  10. importorg.apache.mina.filter.codec.ProtocolCodecFilter;
  11. importorg.apache.mina.filter.codec.textline.TextLineCodecFactory;
  12. importorg.apache.mina.filter.logging.LoggingFilter;
  13. importorg.apache.mina.filter.ssl.SslFilter;
  14. importorg.apache.mina.transport.socket.nio.NioSocketConnector;
  15. publicclassSSLClient
  16. {
  17. privatestaticfinalintREMORT_PORT=5000;
  18. publicstaticvoidmain(String[]args)throwsIOException,InterruptedException,GeneralSecurityException
  19. {
  20. IoConnectorconnector=newNioSocketConnector();
  21. connector.getSessionConfig().setReadBufferSize(2048);
  22. SSLContextsslContext=newSSLContextGenerator().getSslContext();
  23. System.out.println("SSLContextprotocolis:"+sslContext.getProtocol());
  24. SslFiltersslFilter=newSslFilter(sslContext);
  25. sslFilter.setUseClientMode(true);
  26. connector.getFilterChain().addFirst("sslFilter",sslFilter);
  27. connector.getFilterChain().addLast("logger",newLoggingFilter());
  28. connector.getFilterChain().addLast("codec",newProtocolCodecFilter(newTextLineCodecFactory(Charset.forName("UTF-8"))));
  29. connector.setHandler(newSSLClientHandler("HelloServer.."));
  30. ConnectFuturefuture=connector.connect(newInetSocketAddress("172.108.0.6",REMORT_PORT));
  31. future.awaitUninterruptibly();
  32. if(!future.isConnected())
  33. {
  34. return;
  35. }
  36. IoSessionsession=future.getSession();
  37. session.getConfig().setUseReadOperation(true);
  38. session.getCloseFuture().awaitUninterruptibly();
  39. System.out.println("AfterWriting");
  40. connector.dispose();
  41. }
  42. }
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代码
  1. packagecom.sample.ssl;
  2. importorg.apache.mina.core.service.IoHandlerAdapter;
  3. importorg.apache.mina.core.session.IoSession;
  4. importorg.slf4j.Logger;
  5. importorg.slf4j.LoggerFactory;
  6. publicclassSSLClientHandlerextendsIoHandlerAdapter
  7. {
  8. privatefinalLoggerlogger=(Logger)LoggerFactory.getLogger(getClass());
  9. privatefinalStringvalues;
  10. privatebooleanfinished;
  11. publicSSLClientHandler(Stringvalues)
  12. {
  13. this.values=values;
  14. }
  15. publicbooleanisFinished()
  16. {
  17. returnfinished;
  18. }
  19. @Override
  20. publicvoidsessionOpened(IoSessionsession)
  21. {
  22. session.write(values);
  23. }
  24. @Override
  25. publicvoidmessageReceived(IoSessionsession,Objectmessage)
  26. {
  27. logger.info("Messagereceivedintheclient..");
  28. logger.info("Messageis:"+message.toString());
  29. }
  30. @Override
  31. publicvoidexceptionCaught(IoSessionsession,Throwablecause)
  32. {
  33. session.close();
  34. }
  35. }
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代码
  1. Urlis:/home/giftsam/Desktop/certificates/keystore
  2. SSLProvideris:SunJSSEversion1.6
  3. SSLsupportisadded..
  4. ServerStarted..
  5. Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog
  6. INFO:CREATED
  7. Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog
  8. INFO:OPENED
  9. Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog
  10. INFO:RECEIVED:HeapBuffer[pos=0lim=15cap=36:48656C6C6F205365727665722E2E0A]
  11. Messagereceivedintheserver..
  12. Messageis:HelloServer..
  13. Dec10,20108:38:09PMorg.apache.mina.filter.logging.LoggingFilterlog
  14. INFO:IDLE
  15. Dec10,20108:38:09PMcom.sample.ssl.SSLServerHandlersessionIdle
  16. INFO:Transactionisidlefor10secs,Sodisconnecting..
  17. Dec10,20108:38:09PMorg.apache.mina.filter.logging.LoggingFilterlog
  18. 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代码
  1. Urlis:/home/giftsam/Desktop/certificates/keystore
  2. SSLProvideris:SunJSSEversion1.6
  3. SSLContextprotocolis:TLS
  4. Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog
  5. INFO:CREATED
  6. Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog
  7. INFO:OPENED
  8. Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog
  9. INFO:SENT:HeapBuffer[pos=0lim=15cap=16:48656C6C6F205365727665722E2E0A]
  10. Dec10,20108:37:59PMorg.apache.mina.filter.logging.LoggingFilterlog
  11. INFO:SENT:HeapBuffer[pos=0lim=0cap=0:empty]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值