java netty wss_netty 集成 wss 安全链接

本文介绍了如何在Java Netty框架下集成WSS(WebSocket over SSL)以实现安全链接。通过生成服务器和客户端的证书,详细展示了Netty服务器端和客户端SSL的配置和设置,包括SSLContext、SSLEngine的使用,以及相关源码的解析。
摘要由CSDN通过智能技术生成

虽然我们在内部rpc通信中使用的是基于认证和报文头加密的方式实现安全性,但是有些时候仍然需要使用SSL加密,可能是因为对接的三方系统需要,也可能是由于open的考虑。中午特地测了下netty下集成ssl的功能,关于ssl的握手过程以及java安全框架中的相关组件说明,请参考如下链接:

http://www.cnblogs.com/zhjh256/p/6262620.html

http://www.cnblogs.com/zhjh256/p/6104537.html

网上搜了下,并没有看到完整的netty ssl示例例子,netty in action中也只是匆匆带过。特详细的测试和整理如下。

首先生成服务端证书:

D:\security\server>keytool -genkey -alias securechat -keysize 2048 -validity 365 -keyalg RSA -dname "CN=localhost" -keypass sNetty -storepass sNetty -keystore sChat.jks

D:\security\server>keytool -export -alias securechat -keystore sChat.jks -storepass sNetty -file sChat.cer

存储在文件 中的证书

D:\security\server>cd /d ../client

D:\security\client>keytool -genkey -alias smcc -keysize 2048 -validity 365 -keyalg RSA -dname "CN=localhost" -keypass cNetty -storepass cNetty -keystore cChat.jks

D:\security\client>keytool -import -trustcacerts -alias securechat -file ../server\sChat.cer -storepass cNetty -keystore cChat.jks

所有者: CN=localhost

发布者: CN=localhost

序列号: 78384348

有效期开始日期: Wed Mar 01 12:48:48 CST 2017, 截止日期: Thu Mar 01 12:48:48 CST 2018

证书指纹:

MD5: 94:83:6C:6D:4B:0D:0B:E6:BF:39:B7:2C:17:29:E8:3C

SHA1: 9A:29:27:41:BE:71:38:C8:13:99:3A:8F:C6:37:C2:95:31:14:B4:98

SHA256: E9:31:40:C7:FC:EA:EF:24:54:EF:4C:59:50:44:CB:1F:9A:35:B7:26:07:2D:3B:1F:BC:30:8E:C0:63:45:4F:21

签名算法名称: SHA256withRSA

版本: 3

扩展:

#1: ObjectId: 2.5.29.14 Criticality=false

SubjectKeyIdentifier [

KeyIdentifier [

0000: 9B 96 0D 50 4A 5E AF 3D 56 25 9C A5 69 C1 3E CC ...PJ^.=V%..i.>.

0010: 32 85 0D A8 2...

]

]

是否信任此证书? [否]: 是

证书已添加到密钥库中

netty服务端源码:

48304ba5e6f9fe08f3fa1abda7d326ab.png

package com.ld.net.spider.server;

import io.netty.channel.ChannelHandlerContext;

import io.netty.channel.SimpleChannelInboundHandler;

import java.net.InetSocketAddress;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class SpiderServerBusiHandler extends SimpleChannelInboundHandler {

static final Logger logger = LoggerFactory.getLogger(SpiderServerBusiHandler.class);

@Override

protected void channelRead0(final ChannelHandlerContext ctx, final Object msg)

throws Exception {

System.out.println(msg.toString());

}

@Override

public void exceptionCaught(ChannelHandlerContext ctx,

Throwable cause) throws Exception {

logger.error("channel " + ((InetSocketAddress)ctx.channel().remoteAddress()).toString() + " exception:",cause);

ctx.close();

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

48304ba5e6f9fe08f3fa1abda7d326ab.png

package com.ld.net.spider.channel;

import java.nio.charset.Charset;

import javax.net.ssl.SSLEngine;

import com.ld.net.spider.server.SpiderServerBusiHandler;

import io.netty.channel.Channel;

import io.netty.channel.ChannelInitializer;

import io.netty.channel.ChannelPipeline;

import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

import io.netty.handler.codec.LengthFieldPrepender;

import io.netty.handler.codec.string.StringDecoder;

import io.netty.handler.codec.string.StringEncoder;

import io.netty.handler.ssl.SslContext;

import io.netty.handler.ssl.SslHandler;

public class SslChannelInitializer extends ChannelInitializer {

private final SslContext context;

public SslChannelInitializer(SslContext context) {

this.context = context;

}

@Override

protected void initChannel(Channel ch) throws Exception {

SSLEngine engine = context.newEngine(ch.alloc());

engine.setUseClientMode(false);

ch.pipeline().addFirst("ssl", new SslHandler(engine));

ChannelPipeline pipeline = ch.pipeline();

pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));

pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); //最大16M

pipeline.addLast("decoder", new StringDecoder(Charset.forName("UTF-8")));

pipeline.addLast("encoder", new StringEncoder(Charset.forName("UTF-8")));

pipeline.addLast("spiderServerBusiHandler", new SpiderServerBusiHandler());

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

48304ba5e6f9fe08f3fa1abda7d326ab.png

package com.ld.net.spider.channel;

import io.netty.bootstrap.ServerBootstrap;

import io.netty.buffer.PooledByteBufAllocator;

import io.netty.channel.ChannelOption;

import io.netty.channel.EventLoopGroup;

import io.netty.channel.ServerChannel;

import io.netty.channel.nio.NioEventLoopGroup;

import io.netty.channel.socket.nio.NioServerSocketChannel;

import io.netty.handler.ssl.SslContext;

import io.netty.handler.ssl.SslContextBuilder;

import java.io.FileInputStream;

import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class SocketServerHelper {

static final Logger logger = LoggerFactory.getLogger(SocketServerHelper.class);

private static int WORKER_GROUP_SIZE = Runtime.getRuntime().availableProcessors() * 2;

private static EventLoopGroup bossGroup;

private static EventLoopGroup workerGroup;

private static Class extends ServerChannel> channelClass;

public static void startSpiderServer() throws Exception {

ServerBootstrap b = new ServerBootstrap();

b.childOption(ChannelOption.TCP_NODELAY, true)

.childOption(ChannelOption.SO_KEEPALIVE, true)

.childOption(ChannelOption.SO_REUSEADDR, true)

.childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(false))

.childOption(ChannelOption.SO_RCVBUF, 1048576)

.childOption(ChannelOption.SO_SNDBUF, 1048576);

bossGroup = new NioEventLoopGroup(1);

workerGroup = new NioEventLoopGroup(WORKER_GROUP_SIZE);

channelClass = NioServerSocketChannel.class;

logger.info("workerGroup size:" + WORKER_GROUP_SIZE);

logger.info("preparing to start spider server...");

b.group(bossGroup, workerGroup);

b.channel(channelClass);

KeyManagerFactory keyManagerFactory = null;

KeyStore keyStore = KeyStore.getInstance("JKS");

keyStore.load(new FileInputStream("D:\\security\\server\\sChat.jks"), "sNetty".toCharArray());

keyManagerFactory = KeyManagerFactory.getInstance("SunX509");

keyManagerFactory.init(keyStore,"sNetty".toCharArray());

SslContext sslContext = SslContextBuilder.forServer(keyManagerFactory).build();

b.childHandler(new SslChannelInitializer(sslContext));

b.bind(9912).sync();

logger.info("spider server start sucess, listening on port " + 9912 + ".");

}

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

SocketServerHelper.startSpiderServer();

}

public static void shutdown() {

logger.debug("preparing to shutdown spider server...");

bossGroup.shutdownGracefully();

workerGroup.shutdownGracefully();

logger.debug("spider server is shutdown.");

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

48304ba5e6f9fe08f3fa1abda7d326ab.png

package com.ld.net.spider.channel;

import java.net.InetSocketAddress;

import java.nio.channels.ClosedChannelException;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;

import io.netty.channel.Channel;

import io.netty.channel.ChannelFuture;

public class SocketHelper {

static final Logger logger = LoggerFactory.getLogger(SocketHelper.class);

public static ChannelFuture writeMessage(Channel channel,String msg) {

if(channel!=null){

try {

return channel.writeAndFlush(msg).sync();

} catch (Exception e) {

String otherInfo = "";

if(channel.remoteAddress() != null) {

otherInfo = "remote address [" + ((InetSocketAddress)channel.remoteAddress()).toString() + "]";

} else {

otherInfo = "channel is null.";

}

if(e instanceof ClosedChannelException) {

logger.error("channel to " + otherInfo + " is closed",e);

} else {

logger.error("timeout occured during channel send msg, " + otherInfo,e);

}

}

}else{

logger.error("send msg failed, channel is disconnected or not connect. channel is null, please see caller log.");

}

return null;

}

public static ChannelFuture writeMessage(Channel channel,ByteBuf msg) {

if(channel!=null){

try {

return channel.writeAndFlush(msg).sync();

} catch (Exception e) {

logger.error("timeout occured during channel send msg. remote address is:" + ((InetSocketAddress)channel.remoteAddress()).toString(),e);

}

}else{

logger.error("send msg failed, channel is disconnected or not connect, channel is null, please see caller log.");

}

return null;

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值