Netty之握手和安全认证

Netty之握手和安全认证

    握手的发起是在客户端和服务端TCP链路建立成功通道激活时,握手消息的接入和安全认证在服务端处理。

一. 握手认证的客户端ChannelHandler

    握手认证的客户端ChannelHandler,用于在通道激活时发起握手请求

package aggrement;

 

import java.awt.TrayIcon.MessageType;

 

importio.netty.channel.ChannelHandlerAdapter;

import io.netty.channel.ChannelHandlerContext;

/*

 * 握手认证客户端,用于在通道激活时发起握手请求

 */

public class LoginAuthReqHandler extendsChannelHandlerAdapter{

        

         /*

          * 当客户端跟服务端TCP三次握手成功之后,由客户端构造握手请求消息发送给服务端

          * 由于采用IP白名单认证机制,因此,不需要携带消息体,消息体为空,消息类型为3

          * 握手请求消息,握手请求发送之后,按照协议规范,服务端需要返回握手应答消息

          * (non-Javadoc)

          * @seeio.netty.channel.ChannelHandlerAdapter#channelActive(io.netty.channel.ChannelHandlerContext)

          */

         publicvoid channelActive(ChannelHandlerContext ctx) throws Exception{

                   ctx.writeAndFlush(buildLoginReq());

         }

    

         /*

          * 对握手应答消息进行处理,首先判断消息是否是握手应答消息

          * 如果不是,直接透传给后面的ChannelHandler进行处理;首先判断是握手应答消息

          * 对应答结果进行判断

          * (non-Javadoc)

          * @seeio.netty.channel.ChannelHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext,java.lang.Object)

          */

         publicvoid channelRead(ChannelHandlerContext ctx,Object msg) throws Exception{

                   NettyMessagemessage=(NettyMessage) msg;

                   //如果是握手应答消息,需要判断是否认证成功

                   if(message.getHeader()!=null)&&

                   message.getHeader().getType()==MessageType.LOGIN_RESP.value()){

                            byteloginResult=(byte) message.getBody();

                            if(loginResult!=(byte)0) {

                                     //握手失败,关闭连接

                                     ctx.close();

                            }else {

                                     System.out.println("Loginis ok:"+message);

                                     ctx.fireChannelRead(msg);

                            }

                   }  else

                            ctx.fireChannelRead(msg);

         }

                  

         privateNettyMessage buildLoginReq(){

                   NettyMessagemessage=new NettyMessage();

                   Headerheader=new Header();

                   header.setType(MessageType.LOGIN_REQ.value());

                   message.setHeader(header);

                   returnmessage;

         }

        

         publicvoid exceptionCaught(ChannelHandlerContext ctx,Throwable cause) throwsException{

                   ctx.fireExceptionCaught(cause);

         }

}

二.服务端握手接入和安全认证LoginAuthRespHandler

package aggrement;

 

importio.netty.channel.ChannelHandlerAdapter;

importio.netty.channel.ChannelHandlerContext;

 

import java.awt.TrayIcon.MessageType;

import java.net.InetSocketAddress;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

/*

 * 服务端的握手接入和安全认证

 */

public class LoginAuthRespHandler extendsChannelHandlerAdapter{

   

         privateMap nodeCheck=newConcurrentHashMap();

         //分别定义了重复登录保护和IP认证的白名单列表,主要用于提升握手的可靠性

         privateString[] whitekList={"127.0.0.1","192.168.1.104"};

        

         @Override

         publicvoid channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {

                   NettyMessagemessage=(NettyMessage) msg;

                  

                   /*

                    * 用于接入认证,首先根据客户端的原地址(/127.0.0.1:12088)进行重复登录判断

                    * 如果客户端已经登录成功,拒绝重复登录,以防止由于客户端重复登录导致的句柄泄漏

                    *

                    */

                   //如果是握手请求消息,处理,其他消息透传

                   if(message.getHeader()!=null&&message.getHeader().getType()==MessageType.LOGIN_REQ.value)){

                            StringnodeIndex=ctx.channel().remoteAddress().toString();

                            NettyMessageloginResp=null;

                            //重复登录,拒绝

                            if(nodeCheck.containsKey(nodeIndex)){

                                     loginResp=buildResponse((byte)-1);

                            }  else{

                                     //通过ChannelHandlerContext的Channel接口获取客户端的

                                     //InetSocketAddress地址,从中取得发送方的原地址信息,通过原地址进行白名单校验

                                     //校验通过握手成功,否则握手失败,

                                     InetSocketAddressaddress=(InetSocketAddress) ctx.channel().remoteAddress();

                                     Stringip=address.getAddress().getHostAddress();

                                     booleanisOK=false;

                                     for(StringWIP:whiteList){

                                               if(WIP.equals(ip)){

                                                        isIK=true;

                                                        break;

                                               }

                                     }

                                     //通过buildResponse构造握手应答消息返回客户端

                                     loginResp=isOK?buildResponse((byte)0):buildResponse((byte) -1);

                                     if(isOK)

                                               nodeCheck.put(nodeIndex,true);

                            }

                            System.out.println("Thelogin responseis:"+loginResp+"body["+loginResp.getBody()+"]");

                            ctx.writeAndFlush(loginResp);

                           

                   }else {

                            ctx.fireChannelRead(msg);

                   }

         }

        

         privateNettyMessage buildResponse(byte result){

                   NettyMessagemessge=new NettyMessage();

                   Headerheader=new Header();

                   header.setType(MessageType.LOGIN_RESP.value());

                   message.setHeader(header);

                   message.setBody(result);

                   returnmessage;

         }

        

         publicvoid exceptionCautht(ChannelHandlerContext ctx,Throwable cause) throwsException{

                   nodeCheck.remove(ctx.channel().remoteAddress().toString());

                   ctx.close();

                   ctx.fireExceptionCautht(cause);

         }

}

    当发生异常关闭链路的时候,需要将客户端的消息从登录注册表中去注册,以保证后续客户端可以重连成功。

 

 

 

你可能感兴趣的:(Netty)