项目系统Netty的Channel和用户之间的关系绑定正确做法,以及Channel通道的安全性方案
前言
考虑一个功能业务,在web
程序中向指定的某个用户进行实时通讯
在Web运用的Socket
通讯功能中(如在线客服),为保证点对点通讯.而这个看似简单的根据用户寻到起channel
通道实际会碰到不少问题
- web程序中的
Http
协议是无状态的 - 一般项目中
socket
服务和web
项目是独立部署的 socket
连接存在重连的情况,而Channel
对象每次都不一样Channel
是面向网卡绑定的,无法序列化
解决方案
通过管理一个线程安全的用户标识
(如用户主键)和对应channel
的map
链表
private final ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();
那么问题来了,
- 在
netty
模块中怎么得到这个用户标识
? - 又如何保证
netty socket
模块可以安全的识别某个通道属于某个用户?(这个可以像上面一样的方式解决) netty socket
模块接收到一条消息又任何证明这条通道是可信的?
在netty
的实现中是没有认证也没有HttpSession
这个东西的,也就是说.在netty
程序线程中是无法得到web项目登录的用户情况的.
出于这点,参考web
项目集群的session
共享方案.可以在Redis等缓存中保存登录信息.
- 在
web
项目中登录之后在redis中在这个以用户id
为名的key
中保存一个token
, - 在客户端
socket
通道建立之后立马发送包含一个用户标识
和ASK
到socket
服务端, - 服务端根据
ASK
计算一个token
和redis
比对.一旦比对成功,则绑定当前channel
和用户之间的关系; - 之后
server
每接收到一条消息就检测当前通道有没有绑定用户信息
这个
key
是一次性的.这点非常重要,试想一下.在你前台项目可能因为cookie过期或者后台已经自动将该用户下线,而你的用户标识
和ASK
暴露.那么就可能被恶意连接发送消息;
另外关于token
和ASK
之类的验证传输如果仅仅是为了识别和绑定用户与channel
的关系,这点也是可以忽略的,只要redis中保存该用户的登录状态即可,通道建立的第一次通讯就传输当前浏览器的登录用户标识,再去redis中比对即可,但是redis中的这个key
还是一次性的好,避免一个用户建立多条socket
通道
正确的绑定通道Channel
和用户之间的关系
如果我们仅仅有一个ConcurrentHashMap<String, Channel>
,是无法快速优雅的判断当前channel
是属于哪个用户的;我看到别人绝大多数的实现是在创建一个channelId
和用户标识
的Map来管理
//key为channel的长id,channel.id().asLongText();value为用户id
private final ConcurrentHashMap<String, String> channelAndUserMap = new ConcurrentHashMap<>();
其实这不是最合理的做法,正确的做法是利用Channel
对象提供的AttributeMap
来保存该通道的附带信息,很多人不知道Channel
对象提供了一个绑定自定义数据的Map
使用示例
//用户id=>channel示例
private final ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();
/**
* 判断一个通道是否有用户在使用
* 可做信息转发时判断该通道是否合法
* @param channel
* @return
*/
public boolean hasUser(Channel channel) {
AttributeKey<String> key = AttributeKey.valueOf("user");
return (channel.hasAttr(key) || channel.attr(key).get() != null);//netty移除了这个map的remove方法,这里的判断谨慎一点
}
/**
* 上线一个用户
*
* @param channel
* @param userId
*/
public void online(Channel channel, String userId) {
//先判断用户是否在web系统中登录?
//这部分代码个人实现,参考上面redis中的验证
this.channelMap.put(userId, channel);
AttributeKey<String> key = AttributeKey.valueOf("user");
channel.attr(key).set(userId);
}
/**
* 根据用户id获取该用户的通道
*
* @param userId
* @return
*/
public Channel getChannelByUserId(String userId) {
return this.channelMap.get(userId);
}
/**
* 判断一个用户是否在线
*
* @param userId
* @return
*/
public Boolean online(String userId) {
return this.channelMap.containsKey(userId) && this.channelMap.get(userId) != null;
}
注意!!
很多人拿channel.id().asShortText()
来记录标识channel
,这是错误的!!!!!短id不保证全局唯一!!
项目系统Netty的Channel和用户之间的关系绑定正确做法,以及Channel通道的安全性方案的更多相关文章
- 如何理解springcloud微服务项目中,eureka,provider,consumer它们之间的关系?
eureka负责注册provider和consumer的服务信息 provider负责与数据库进行交互,实现数据持久化,并给consumer提供服务 consumer与前端交互,通过与Eureka同源 ...
- 关于计算机的ID和用户ID之间的关系
关于计算机的ID和用户ID之间的关系 计算机安装完系统后就会生成计算机ID,然后系统会以计算机ID为前缀附加数字创建Administrator(500)和Guest(501)用户ID,其他用户的ID将 ...
- GJM :用JIRA管理你的项目(三)基于LDAP用户管理 [转载]
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- PostgreSQL表空间、数据库、模式、表、用户/角色之间的关系
看PostgreSQL9的官方文档,我越看越迷糊,这表空间,数据库,模式,表,用户,角色之间的关系怎么在PostgreSQL里这么混乱呢?经过中午的一个小实验,我逐渐理清了个中来龙去脉.下面我来还原我 ...
- PostgreSQL表空间、模式、表、用户/角色之间的关系
PostgreSQL表空间.模式.表.用户/角色之间的关系是本文我们主要要介绍的内容,表空间,数据库,模式,表,用户,角色之间的关系到底是怎样的呢?接下来我们就开始介绍这一过程. 实验出角色与用户的关 ...
- 使用Jquery+EasyUI 进行框架项目开发案例讲解之二---用户管理源码分享
使用Jquery+EasyUI 进行框架项目开发案例讲解之二 用户管理源码分享 在上一篇文章<使用Jquery+EasyUI进行框架项目开发案例讲解之一---员工管理源码分享>我们分享 ...
- 使用Jquery+EasyUI 进行框架项目开发案例解说之二---用户管理源代码分享
使用Jquery+EasyUI 进行框架项目开发案例解说之二 用户管理源代码分享 在上一篇文章<使用Jquery+EasyUI进行框架项目开发案例解说之中的一个---员工管理源代码分享> ...
- “MVC+Nhibernate+Jquery-EasyUI” 信息发布系统 第四篇(用户管理功能的实现)
“MVC+Nhibernate+Jquery-EasyUI” 信息发布系统 第四篇(用户管理功能的实现) 一.前三篇的内容是否对您有帮助呢?如果有的话,请您继续关注这篇吧,这篇主要是实现”用户管理“的 ...
- Linux 普通用户之间免密登陆
目的: 同台机器之间实现普通用户之间的免密登陆: NN01 的user1 免密登陆 user2 不同机器之间实现普通用户之间的免密登陆 :NN01 的user1 免密登陆 NN01 的user1 一. ...
随机推荐
- Excel提取身份证年龄和性别③
问题场景 从user表中的身份信息中拿到用户的年龄和性别: 以下方法也可适用于提取其他数据,目的在于通过实例操作了解更多函数用法: 以下图中数据都为测试数据,不具备真实性! 场景一 从user表中的1 ...
- 计算机网络-应用层(5)P2P应用
P2P系统的索引:信息到节点位置(IP地址+端口号)的映射 在文件共享(如电驴中):利用索引动态跟踪节点所共享的文件的位置.节点需要告诉索引它拥有哪些文件.节点搜索索引从而获知能够得到哪些文件 在即时 ...
- muduo源码解析4-exception类
exception class exception:public std::exception { }; 作用: 实现了一个异常类,继承于std::exception,主要用于实现打印线程调用栈信息. ...
- Spring Cloud系列(一):微服务架构简介
一.微服务概述 1.微服务是什么 微服务架构的核心就是服务的拆分,把传统的单体式应用,根据一定的维度(比如业务)拆分为一个一个的服务,每一个服务都有自身特定的功能,又都能够独立的部署,甚至可以拥有自己 ...
- 极简 Node.js 入门 - 3.5 文件夹操作
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- Centos7安装Oracle12c教程
12c数据库 创建oracle的系统用户和用户组 [root@localhost /]# groupadd oinstall [root@localhost /]# groupadd dba [roo ...
- 路由策略Routing Policy和策略路由PBR的区别
这是面试的时候问道的一个问题,这里跟大家分享一下 路由策略(Routing Policy)是为了改变网络流量所经过的途径而修改路由信息的技术: PBR(policy-based-route)是一种依据 ...
- Linux 基础指令2
管道符| 先执行第一个命令后执行第二个 eg:查看文件中间几行: head -n1 文件名| tail -n2 :先查看文件前n1行,然后在n1行中的后n2行 tail -n1 文件名| head - ...
- 什么是Nginx -九五小庞
- nginx模块化结构
NGINX是一个免费.开源.高性能.轻量级的HTTP和反向代理服务器,也是一个电子邮件(IMAP/POP3)代理服务器 特点: 占有内存少,并发能力强 Nginx的优点: 模块化.事件驱动.异步.非阻 ...