您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Netty與Qt如何實(shí)現(xiàn)wss雙向認(rèn)證”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Netty與Qt如何實(shí)現(xiàn)wss雙向認(rèn)證”吧!
Netty 4.1.42.Final + Qt 5.9 + SpringBoot2.1.8
要使用ssl雙向驗(yàn)證,就必須先要生成服務(wù)端和客戶端的證書,并相互添加信任,具體流程如下(本人調(diào)試這個(gè)用例的時(shí)候,花了很多時(shí)間來驗(yàn)證證書是否正確,以及握手失敗的原因,這里證書生成過程只要按流程走,本人能保證絕對(duì)沒有問題) 現(xiàn)在打開cmd,在哪個(gè)目錄下打開,證書就會(huì)放在哪個(gè)目錄下:
keytool -genkey -alias securechat -keysize 2048 -validity 365 -keyalg RSA -dname "CN=localhost" -keypass sNetty -storepass sNetty -keystore sChat.jks -deststoretype pkcs12
-keysize 2048 密鑰長度2048位(這個(gè)長度的密鑰目前可認(rèn)為無法被暴力破解)
-validity 365 證書有效期365天
-keyalg RSA 使用RSA非對(duì)稱加密算法
-dname "CN=localhost" 設(shè)置Common Name為localhost
-keypass sNetty密鑰的訪問密碼為sNetty
-storepass sNetty密鑰庫的訪問密碼為sNetty(其實(shí)這兩個(gè)密碼也可以設(shè)置一樣,通常都設(shè)置一樣,方便記)
-keystore sChat.jks 指定生成的密鑰庫文件為sChata.jks
-deststoretype pkcs12 必須要pkcs12
keytool -export -alias securechat -keystore sChat.jks -storepass sNetty -file sChat.cer
keytool -genkey -alias smcc -keysize 2048 -validity 365 -keyalg RSA -dname "CN=localhost" -keypass sNetty -storepass sNetty -keystore cChat.jks -deststoretype pkcs12
keytool -import -trustcacerts -alias securechat -file sChat.cer -storepass sNetty -keystore cChat.jks
keytool -export -alias smcc -keystore cChat.jks -storepass sNetty -file cChat.cer
keytool -import -trustcacerts -alias smcc -file cChat.cer -storepass sNetty -keystore sChat.jks
到這里,證書就生成完畢了,我們就可以得到兩個(gè)jks文件,一個(gè)是服務(wù)端的sChat.jks ,一個(gè)是客戶端的cChat.jks ,這兩個(gè)文件后面初始化sslCOntext的時(shí)候會(huì)用到
package com.cccc.ocpptest; import java.io.FileInputStream; import java.io.IOException; import java.security.KeyStore; import java.security.NoSuchAlgorithmException; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; /** * ContextSSLFactory * * @author MFY * @date 2019/10/1 */ public class ContextSSLFactory { private static final SSLContext SSL_CONTEXT_S ; private static final SSLContext SSL_CONTEXT_C ; static{ SSLContext sslContext = null ; SSLContext sslContext2 = null ; try { sslContext = SSLContext.getInstance("TLSv1") ; sslContext2 = SSLContext.getInstance("TLSv1") ; } catch (NoSuchAlgorithmException e1) { e1.printStackTrace(); } try{ if(getKeyManagersServer() != null && getTrustManagersServer() != null ){ sslContext.init(getKeyManagersServer(), getTrustManagersServer(), null); } if(getKeyManagersClient() != null && getTrustManagersClient() != null){ sslContext2.init(getKeyManagersClient(), getTrustManagersClient(), null); } }catch(Exception e){ e.printStackTrace() ; } sslContext.createSSLEngine().getSupportedCipherSuites() ; sslContext2.createSSLEngine().getSupportedCipherSuites() ; SSL_CONTEXT_S = sslContext ; SSL_CONTEXT_C = sslContext2 ; } public ContextSSLFactory(){ } public static SSLContext getSslContext(){ return SSL_CONTEXT_S ; } public static SSLContext getSslContext2(){ return SSL_CONTEXT_C ; } private static TrustManager[] getTrustManagersServer(){ FileInputStream is = null ; KeyStore ks = null ; TrustManagerFactory keyFac = null ; TrustManager[] kms = null ; try { // 獲得KeyManagerFactory對(duì)象. 初始化位默認(rèn)算法 keyFac = TrustManagerFactory.getInstance("SunX509") ; is =new FileInputStream( "D:\\work\\JavaProjects\\ocpptest\\keys\\sChat.jks" ); ks = KeyStore.getInstance("JKS") ; String keyStorePass = "sNetty" ; ks.load(is , keyStorePass.toCharArray()) ; keyFac.init(ks) ; kms = keyFac.getTrustManagers() ; } catch (Exception e) { e.printStackTrace(); } finally{ if(is != null ){ try { is.close() ; } catch (IOException e) { e.printStackTrace(); } } } return kms ; } private static TrustManager[] getTrustManagersClient(){ FileInputStream is = null ; KeyStore ks = null ; TrustManagerFactory keyFac = null ; TrustManager[] kms = null ; try { // 獲得KeyManagerFactory對(duì)象. 初始化位默認(rèn)算法 keyFac = TrustManagerFactory.getInstance("SunX509") ; is =new FileInputStream( "D:\\work\\JavaProjects\\ocpptest\\keys\\cChat.jks" ); ks = KeyStore.getInstance("JKS") ; String keyStorePass = "sNetty" ; ks.load(is , keyStorePass.toCharArray()) ; keyFac.init(ks) ; kms = keyFac.getTrustManagers() ; } catch (Exception e) { e.printStackTrace(); } finally{ if(is != null ){ try { is.close() ; } catch (IOException e) { e.printStackTrace(); } } } return kms ; } private static KeyManager[] getKeyManagersServer(){ FileInputStream is = null ; KeyStore ks = null ; KeyManagerFactory keyFac = null ; KeyManager[] kms = null ; try { // 獲得KeyManagerFactory對(duì)象. 初始化位默認(rèn)算法 keyFac = KeyManagerFactory.getInstance("SunX509") ; is =new FileInputStream( "D:\\work\\JavaProjects\\ocpptest\\keys\\sChat.jks" ); ks = KeyStore.getInstance("JKS") ; String keyStorePass = "sNetty" ; ks.load(is , keyStorePass.toCharArray()) ; keyFac.init(ks, keyStorePass.toCharArray()) ; kms = keyFac.getKeyManagers() ; } catch (Exception e) { e.printStackTrace(); } finally{ if(is != null ){ try { is.close() ; } catch (IOException e) { e.printStackTrace(); } } } return kms ; } private static KeyManager[] getKeyManagersClient(){ FileInputStream is = null ; KeyStore ks = null ; KeyManagerFactory keyFac = null ; KeyManager[] kms = null ; try { // 獲得KeyManagerFactory對(duì)象. 初始化位默認(rèn)算法 keyFac = KeyManagerFactory.getInstance("SunX509") ; is =new FileInputStream("D:\\work\\JavaProjects\\ocpptest\\keys\\cChat.jks"); ks = KeyStore.getInstance("JKS") ; String keyStorePass = "sNetty" ; ks.load(is , keyStorePass.toCharArray()) ; keyFac.init(ks, keyStorePass.toCharArray()) ; kms = keyFac.getKeyManagers() ; } catch (Exception e) { e.printStackTrace(); } finally{ if(is != null ){ try { is.close() ; } catch (IOException e) { e.printStackTrace(); } } } return kms ; } }
package com.cccc.ocpptest; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.FullHttpRequest; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.UrlEncoded; @ChannelHandler.Sharable public class CustomUrlHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 只針對(duì)FullHttpRequest類型的做處理,其它類型的自動(dòng)放過 if (msg instanceof FullHttpRequest) { FullHttpRequest request = (FullHttpRequest) msg; String uri = request.uri(); int idx = uri.indexOf("?"); if (idx > 0) { String query = uri.substring(idx + 1); // uri中參數(shù)的解析使用的是jetty-util包,其性能比自定義及正則性能高。 MultiMap<String> values = new MultiMap<String>(); UrlEncoded.decodeTo(query, values, "UTF-8"); request.setUri(uri.substring(0, idx)); } } ctx.fireChannelRead(msg); } }
package com.cccc.ocpptest; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.slf4j.Logger; import org.slf4j.LoggerFactory; //import java.net.InetAddress; @ChannelHandler.Sharable public class MyWebSocketHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = LoggerFactory.getLogger(MyWebSocketHandler.class); @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { logger.info("與客戶端建立連接,通道開啟"); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { logger.info("與客戶端斷開連接,通道關(guān)閉"); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { TextWebSocketFrame message = (TextWebSocketFrame) msg; logger.info("服務(wù)端收到數(shù)據(jù): " + message.text()); // 此處需注意返回的數(shù)據(jù)的格式為TextWebSocketFrame。否則客戶端收不到消息 ctx.channel().writeAndFlush(new TextWebSocketFrame(message.text())); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { logger.error(cause.getMessage()); // cause.printStackTrace(); } }
package com.cccc.ocpptest; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.net.ssl.SSLEngine; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.handler.ssl.SslHandler; import io.netty.handler.stream.ChunkedWriteHandler; import org.springframework.stereotype.Component; /** * NettySocketServer * * @author MFY * @date 2019/10/1 */ @Component public class NettySocketServer { private static SslHandler sslHandler = null ; private EventLoopGroup bossGroup = null ; private EventLoopGroup workerGroup = null ; @PostConstruct public void start(){ bossGroup = new NioEventLoopGroup() ; workerGroup = new NioEventLoopGroup() ; try{ ServerBootstrap serverStrap = new ServerBootstrap() ; serverStrap.group(bossGroup , workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) .option(ChannelOption.SO_KEEPALIVE, true) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000 * 5 * 60) .handler(new LoggingHandler(LogLevel.DEBUG)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pie = socketChannel.pipeline() ; pie.addLast(new HttpServerCodec()); pie.addLast(new HttpObjectAggregator(65535)); pie.addLast(new ChunkedWriteHandler()); // 對(duì)websocket url中的參數(shù)做解析處理的Handler pie.addLast(new CustomUrlHandler()); // 對(duì)websocket做支持,其路徑為/ws pie.addLast(new WebSocketServerProtocolHandler("/ws")); // 自定義業(yè)務(wù)邏輯處理的Handler pie.addLast(new MyWebSocketHandler()); SSLEngine engine = ContextSSLFactory.getSslContext().createSSLEngine(); engine.setUseClientMode(false); engine.setNeedClientAuth(true); pie.addFirst("ssl", new SslHandler(engine)); } }); serverStrap.bind(30021).sync() ; System.out.println("服務(wù)已開啟"); }catch(Exception e){ e.printStackTrace() ; bossGroup.shutdownGracefully() ; workerGroup.shutdownGracefully() ; } } private SslHandler getSslHandler(){ if(sslHandler == null ){ SSLEngine sslEngine = ContextSSLFactory.getSslContext().createSSLEngine() ; sslEngine.setUseClientMode(false) ; //false為單向認(rèn)證,true為雙向認(rèn)證 sslEngine.setNeedClientAuth(true) ; sslHandler = new SslHandler(sslEngine); } return sslHandler ; } @PreDestroy public void close(){ bossGroup.shutdownGracefully() ; workerGroup.shutdownGracefully() ; } // public static void main(String[] args) { // new NettySocketServer().start() ; // } }
package com.cccc.ocpptest; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class OcpptestApplication { public static void main(String[] args) { SpringApplication.run(OcpptestApplication.class, args); } }
三、Qt Wss測試
#include <QCoreApplication> #include <QWebSocket> #include <QNetworkRequest> #include <QDebug> #include <QSslConfiguration> #include <QSslCertificate> #include <QFile> #include <QSslKey> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QWebSocket webSocket; QObject::connect(&webSocket, &QWebSocket::connected, [](){ qDebug() << "connected"; }); QObject::connect(&webSocket, &QWebSocket::disconnected, [](){ qDebug() << "disconnected"; }); QObject::connect(&webSocket,(void(QWebSocket::*)(QAbstractSocket::SocketError)) &QWebSocket::error, [&webSocket](QAbstractSocket::SocketError){ qDebug() << webSocket.errorString(); }); QFile cerFile1("D:/work/JavaProjects/ocpptest/keys/cChat.jks"); if (cerFile1.open(QFile::ReadOnly)) { QSslKey sslKey; QSslCertificate sslCer; QList<QSslCertificate> caCers; if (QSslCertificate::importPkcs12(&cerFile1, &sslKey, &sslCer, &caCers, "sNetty")) { qDebug() << "OK"; QSslConfiguration sslConfig; sslConfig.setCaCertificates(caCers); sslConfig.setPrivateKey(sslKey); sslConfig.setLocalCertificate(sslCer); sslConfig.setProtocol(QSsl::AnyProtocol); webSocket.setSslConfiguration(sslConfig); QUrl url("wss://localhost:8000/ws"); QNetworkRequest request(url); webSocket.open(request); } cerFile1.close(); } return a.exec(); }
到此,相信大家對(duì)“Netty與Qt如何實(shí)現(xiàn)wss雙向認(rèn)證”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。