netty实现SSL 双向认证与用jmeter测试

 有时RestApi接口需要实现双向认证,验证客户端请求的合法来源,这里用netty实现了https请求的双向认证

首先ide里生成一个maven项目,pom.xml加入netty依懒包

 
 <dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.20.Final</version>
</dependency>

 一、   openssl生成证书

  sslauth建立目录security存放证书,

注意生成证书common-name参数为localhost,用于本地测试,“A challenge password”可不输

 1. 建立root CA

  security目录下执行下列命令,建立要证书,用来做签名CA证书

  • openssl genrsa -out rootCA.key 2048
  •  openssl req -x509 -new -nodes -key rootCA.key -days   1024 -out rootCA.pem

 2. 建立服务端证书

  security建立service目录,存放服务端证书

  • openssl genrsa -out service/service.key 2048
  • openssl req -new -key service/service.key -out service/service.csr
  • openssl x509 -req -in service/service.csr -CA ./rootCA.pem -CAkey ./rootCA.key -CAcreateserial -out service/service.crt -days 500 -sha256
  • openssl pkcs8 -topk8 -inform PEM -outform PEM -in service/service.key -out service/service.pkcs8.key -nocrypt

3. 建立客户端证书

   security建立client目录,存放客户端证书

  • openssl genrsa -out client/client.key 2048
  • openssl req -new -key client/client.key -out client/client.csr
  • openssl x509 -req -in client/client.csr -CA ./rootCA.pem -CAkey ./rootCA.key -CAcreateserial -out client/client.crt -days 500 -sha256
  • openssl pkcs8 -topk8 -inform PEM -outform PEM -in client/client.key -out client/client.pkcs8.key -nocrypt

二、   建立netty https

 1. 建立DefaultRequestHandler

  用来处理用户请求,输出HelloWorld

public class DefaultRequestHandler extends ChannelInboundHandlerAdapter {
    private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };

    private static final AsciiString CONTENT_TYPE = AsciiString.cached("Content-Type");
    private static final AsciiString CONTENT_LENGTH = AsciiString.cached("Content-Length");
    private static final AsciiString CONNECTION = AsciiString.cached("Connection");
    private static final AsciiString KEEP_ALIVE = AsciiString.cached("keep-alive");

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof HttpRequest) {
            HttpRequest req = (HttpRequest) msg;

            boolean keepAlive = HttpUtil.isKeepAlive(req);
            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(CONTENT));
            response.headers().set(CONTENT_TYPE, "text/plain");
            response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());

            if (!keepAlive) {
                ctx.write(response).addListener(ChannelFutureListener.CLOSE);
            } else {
                response.headers().set(CONNECTION, KEEP_ALIVE);
                ctx.write(response);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

 

2. 建立PipelineInitializer

 初始化netty pipelline,加入ssl handler

public class PipelineInitializer extends ChannelInitializer<SocketChannel> {
    private final SslContext sslCtx;

    public PipelineInitializer(SslContext sslCtx) {
        this.sslCtx = sslCtx;
    }

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        if (sslCtx != null) {
            pipeline.addLast(sslCtx.newHandler(ch.alloc()));
        }
        pipeline.addLast("decoder", new HttpRequestDecoder());
        pipeline.addLast("encoder", new HttpResponseEncoder());
        pipeline.addLast("aggregator", new HttpObjectAggregator(20480));
        pipeline.addLast("chunkWriter", new ChunkedWriteHandler());
        pipeline.addLast(new DefaultRequestHandler());
    }
}

 

3. 建立Server

       应用主类,启动应用,接收4个参数:应用的端口、服务端证书(service/ service.crt)、服务端私钥(service/ service.pkcs8.key)、根证书(rootCA.pem)

         public final class Server {
    static int PORT = 8443;
    public static void main(String[] args) throws Exception {
        if (args.length < 4) {
            System.err.println("args=: port cert privateKey caKey");
            System.exit(1);
        }
        final SslContext sslCtx;
        PORT = Integer.parseInt(args[0]);
        File cert = new File(args[1]);
        File priKey = new File(args[2]);
        File caKey = new File(args[3]);
        sslCtx = SslContextBuilder.forServer(cert, priKey)
                .clientAuth(ClientAuth.REQUIRE)
                .trustManager(caKey).build();
        // Configure the server.
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.option(ChannelOption.SO_BACKLOG, 1024);
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new PipelineInitializer(sslCtx));
            Channel ch = b.bind(PORT).sync().channel();
            System.err.println("https://127.0.0.1:" + PORT + '/');
            ch.closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

 

三、   jmeter测试

1. 启动jmeter

  • 导出客户端证书为p12格式,导出密码:123456

      openssl pkcs12 -export -cacerts -inkey client/client.key -in client/client.crt -out client/client.p12

  • keytool导入根证书,密码:123456

      keytool -import -file ./rootCA.pem -keystore client/ca.jks

  •  启动jmeter

 bin/jmeter -Djavax.net.ssl.trustStore=security/ca.store -Djavax.net.ssl.keyStorePassword=123456 -Djavax.net.ssl.keyStore=security/client/client.p12

2. jmeter测试脚本

新建测试计划=》建立线程组=》建立HTTP请求(路径:https://localhost:8443)=》察看结果树

3. 启动jmeter测试脚本


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值