【netty】netty websocket uri传参问题解析

以前写netty的聊天工具时遇到个问题,就是websocket连接时验证当前用户是否已经拥有登陆权限,

当时想的是像http请求一样,通过url直接传参然后后台解析不通过关闭通道,但是发现url上一增加参数

就无法正常连接,当时时间紧未进行处理,当时处理逻辑如下:

1、先设置读写超时120秒

2、连接成功后增加当前通道验证标识

2、前端监听websocket的onopen方法,一但连接立马发送验证消息,后台验证通过后修改验证标识

3、前端每过50秒向后台发送一个心跳包,后端收到心跳包判断是否已通过验证,通过后回复心跳包,未通过不回复,不回复的话120秒后该通道会被自动关闭

贴下相关代码:

//连接后
		      socket.onopen = function(event) {
		    	  IMSocket.bindUserHandle('${userId}','${sessionId}','online');//绑定通道为当前用户
		    	  openHeartBeat();//开启心跳
		    	  flushNoReadFrendMes();//展示未读消息
		    	  if(layui.layim.cache().mine.status=="online"){
		 	 	     IMSocket.statusnotice('${userId}',3);//通知我上线了	    	 
		 	      }
		    	  if(showclosewebsocketlayer){
		    		  showclosewebsocketlayer=false;
		    		  layer.close(showclosewebsocketindex);
		    	  }
		      };
    /**
     * 消息处理
     *
     * @param hander
     * @param wrapper
     */
    private void receiveMessages(ChannelHandlerContext hander, IMBaseMessage baseMessage) {
    	if(baseMessage.getCmdType()==Constants.CmdType.BIND){//绑定登陆人
    		imConnertor.bindChannel(hander, baseMessage);
		}else if(baseMessage.getCmdType()==Constants.CmdType.MESSAGE){//发送消息
			iLayImMessageService.flushSessionTime(hander);
			baseMessage = iLayImMessageService.saveMessageToDB(baseMessage);
			imConnertor.sendFrendMessage(baseMessage);
		}else if(baseMessage.getCmdType()==Constants.CmdType.READMES){//消息已读
			iLayImMessageService.flushSessionTime(hander);
			iLayImMessageService.readMes(baseMessage);
		}else if(baseMessage.getCmdType()==Constants.CmdType.ONLINE||baseMessage.getCmdType()==Constants.CmdType.OFFLINE){//上线 下线
			List<MyMember> myMembers = iLayImMessageService.userNoticeSatus(baseMessage);
			imConnertor.userNoticeSatus(baseMessage, myMembers);
		}else if(baseMessage.getCmdType()==Constants.CmdType.HEARTBEAT){//心跳
			imConnertor.heartbeat(hander);
		}
    }

 

现在补充另外一种方式基于url参数的验证:

 跟踪源码发现在类WebSocketServerProtocolHandshakeHandler的channelRead方法有判断请求的地址是否与我们开启监听服务的配置的地址是否一样,如果不一样就停止该通道。如图:

class WebSocketServerProtocolHandshakeHandler extends ChannelInboundHandlerAdapter {

    private final String websocketPath;
    private final String subprotocols;
    private final boolean allowExtensions;
    private final int maxFramePayloadSize;
    private final boolean allowMaskMismatch;

    WebSocketServerProtocolHandshakeHandler(String websocketPath, String subprotocols,
            boolean allowExtensions, int maxFrameSize, boolean allowMaskMismatch) {
        this.websocketPath = websocketPath;
        this.subprotocols = subprotocols;
        this.allowExtensions = allowExtensions;
        maxFramePayloadSize = maxFrameSize;
        this.allowMaskMismatch = allowMaskMismatch;
    }

    @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
        final FullHttpRequest req = (FullHttpRequest) msg;
        if (!websocketPath.equals(req.uri())) {
            ctx.fireChannelRead(msg);
            return;
        }

        try {
            if (req.method() != GET) {
                sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
                return;
            }

 发现问题就好处理了,处理如下,将WebSocketServerProtocolHandshakeHandler放在TextWebSocketFrameHandler之后,然后TextWebSocketFrameHandler重写channelRead方法,将url上的参数取出来使用后,将地址设置回去就行了。如果是验证登陆权限的话,验证不能过调用ChannelHandlerContext.close()直接关闭通道,避免资源浪费。

            .childHandler(new ChannelInitializer<Channel>(){//同上
				@Override
				protected void initChannel(Channel ch) throws Exception {
					ChannelPipeline pipeline = ch.pipeline();
			        pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,
			                WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));
			        pipeline.addLast(new HeartbeatServerHandler()); // 2 集成心跳处理
			        pipeline.addLast(new HttpServerCodec());
					pipeline.addLast(new HttpObjectAggregator(64 * 1024));
					pipeline.addLast(new ChunkedWriteHandler());
					pipeline.addLast(new TextWebSocketFrameHandler(iLayImMessageService,imConnertor));
					pipeline.addLast(new WebSocketServerProtocolHandler(WebsocketChatServer.WEB_SOCKET_LINKURL, null, true, 10485760));
					pipeline.addLast(new HttpRequestHandler(WebsocketChatServer.HTTP_SOCKET_LINKURL));
				}})

public class TextWebSocketFrameHandler extends
		SimpleChannelInboundHandler<TextWebSocketFrame> {

	.....

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		if (ObjectHelper.isNotEmpty(msg) && msg instanceof FullHttpRequest) {
			FullHttpRequest request = (FullHttpRequest) msg;
			String uri = request.uri();
			String origin = request.headers().get("Origin");
			if (null == origin) {
				ctx.close();
			} else {
				if (null != uri && uri.contains("?")) {
					String[] uriArray = uri.split("\\?");
					if (null != uriArray && uriArray.length > 1) {
						String[] paramsArray = uriArray[1].split("=");
						if (null != paramsArray && paramsArray.length > 1) {
							//TODO 验证连接权限,不通过关闭
						}
					}
					request.setUri(WebsocketChatServer.WEB_SOCKET_LINKURL);
				}
			}
		}
		super.channelRead(ctx, msg);
	}

    .....

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值