一套简单的web即时通讯——第三版
前言
接上版,本次版本做了如下优化:
1、新增同意、拒绝添加好友后做线上提示;
2、新增好友分组,使用工具生成后台API,新增好友分组功能,主要功能有:添加分组、重命名分组名称、删除分组
3、新增好友管理,主要功能:删除好友(下个版本再实现功能)、移动好友至其他分组
4、添加好友时有验证信息、好友备注、好友分组
5、AIP接口、WebSocket通道的前后端交互采用AES与RSA混合加密,防抓包监听,加、解密操作后并不影响业务,AIP接口、WebSocket通道的前后端交互正常
优化细节
1、新增同意、拒绝添加好友后做线上提示;
2、新增好友分组,使用工具生成后台API,新增好友分组功能,主要功能有:添加分组、重命名分组名称、删除分组
没有分组的默认在列表前面追加,分组名称后面展示对应好友数以及在线好友数量
添加分组、重命名分组名称、删除分组
3、新增好友管理,主要功能:删除好友(下个版本再实现功能)、移动好友至其他分组
移动好友至其他分组
4、添加好友时有验证信息、好友备注、好友分组
先登录两个还不是好友的人,各种新增一个好友分组
A向B发起好友申请
同意好友申请
拒绝好友申请
5、AIP接口、WebSocket通道的前后端交互采用AES与RSA混合加密,防抓包监听,加、解密操作后并不影响业务,AIP接口、WebSocket通道的前后端交互正常
API交互,关于前后端API安全交互,我前段时间实现了一套AES与RSA混合加密,详情请戳:前后端API交互数据加密——AES与RSA混合加密完整实例
WebSocket聊天,webSocket的加、解密与AIP的加、解密原理一样,发送前加密、收到数据后解密再交给业务处理,有个地方要注意的是,我们在进行消息转发时,要用的是接收方的前端公钥进行加密
建立WebSocket连接时,将当前用户的前端公钥发送到后端,后端进行Map保存(只贴出关键代码)
//因为是url的方式传值,公钥中的/需要进行转换一下,传到后端再转回来(PS:因为生成的公钥里是不存在","的,所以这里转成逗号)
websocket = new WebSocket("ws://localhost:10086/websocket/" + userId + "/" + window.jsPublicKey.replace(/\//g,","));
/**
* WebSocket服务
*/
@Component
@ServerEndpoint(value = "/websocket/{userId}/{publicKey}", configurator = MyEndpointConfigure.class)
public class WebSocketServer {
//省略其他代码 /**
* 登录用户的前端公钥Map集合(其实应该放在Redis)
*/
private static Map<Session, String> loginPublicKeyList = new HashMap<Session, String>(); /**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId, @PathParam("publicKey") String publicKey) {
//省略其他代码 //设置前端公钥,因为是url的方式传值,公钥中的/需要进行转换一下,传到后端再转回来,然后将每个用户的前端公钥存储起来
loginPublicKeyList.put(session,publicKey.replaceAll(",", "/")); }
}
前端发送前加密
//发送消息
function send(but) {
//业务操作不变,省略代码 //先加密
let aesKey = aesUtil.genKey();
let data = {
data: aesUtil.encrypt(JSON.stringify({
"type": "1",
"toUser": {"userId": toUserId},
"fromUser": {"userId": fromUserId},
"message": message,
"date": nowTime
}), aesKey),//AES加密后的数据
aesKey: rsaUtil.encrypt(aesKey, sessionStorage.getItem('javaPublicKey')),//后端RSA公钥加密后的AES的key
publicKey: window.jsPublicKey//前端公钥
};
websocket.send(JSON.stringify(data)); //业务操作不变,省略代码
}
后端收到后先解密
/**
* 服务器接收到客户端消息时调用的方法
*/
@OnMessage
public void onMessage(String message, Session session) {
try {
//jackson
ObjectMapper mapper = new ObjectMapper();
//jackson 序列化和反序列化 date处理
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//JSON字符串转 HashMap
HashMap map = mapper.readValue(message, HashMap.class); //先解密
String data = (String) map.get("data");
String aesKey = (String) map.get("aesKey"); //后端私钥解密的到AES的key
byte[] plaintext = RsaUtil.decryptByPrivateKey(Base64.decodeBase64(aesKey), RsaUtil.getPrivateKey());
aesKey = new String(plaintext); //RSA解密出来字符串多一对双引号
aesKey = aesKey.substring(1, aesKey.length() - 1); //AES解密得到明文data数据
String decrypt = AesUtil.decrypt(data, aesKey); //JSON字符串转 HashMap
HashMap hashMap = mapper.readValue(decrypt, HashMap.class); //得到hashMap,下面的业务操作跟前面的一样,这里就不贴出来了 } catch (Exception e) {
e.printStackTrace();
}
}
后端发送之前先加密,这里要用消息接收方的前端公钥进行加密
/**
* 封装一个send方法,发送消息到前端
*/
private void send(Session session, String message) {
try {
//发送前加密
//每次响应之前随机获取AES的key,加密data数据
String key = AesUtil.getKey();
String data = AesUtil.encrypt(message, key);
//用前端的公钥来解密AES的key,并转成Base64,注意:这里需要用接收方的前端公钥进行加密,从loginPublicKeyList集合获取
String aesKey = Base64.encodeBase64String(RsaUtil.encryptByPublicKey(key.getBytes(), loginPublicKeyList.get(session)));
//发送过去的是AES加密后的data,跟RSA加密后的aesKey
session.getBasicRemote().sendText("{\"data\":\"" + data + "\",\"aesKey\":\"" + aesKey + "\"}");
} catch (Exception e) {
e.printStackTrace();
}
}
前端收到消息后先解密
//接收到消息的回调方法
websocket.onmessage = function (event) {
let data = eval("(" + event.data + ")");
//先解密
let msgObj = aesUtil.decrypt(data.data, rsaUtil.decrypt(data.aesKey, window.jsPrivateKey)); //业务操作不变,省略代码 };
上线在线系统通知没有问题
聊天没有问题
后记
第三版先到这里,后面我在整理一下WebSocket的AES与RSA混合加密,单独写一篇博客
一套简单的web即时通讯——第三版的更多相关文章
- 一套简单的web即时通讯——第一版
前言 我们之前已经实现了 WebSocket+Java 私聊.群聊实例,后面我们模仿layer弹窗,封装了一个自己的web弹窗 自定义web弹窗/层:简易风格的msg与可拖放的dialog,生成博客园 ...
- 一套简单的web即时通讯——第二版
前言 接上一版,这一版的页面与功能都有所优化,具体如下: 1.优化登录拦截 2.登录后获取所有好友并区分显示在线.离线好友,好友上线.下线都有标记 3.将前后端交互的值改成用户id.显示值改成昵称ni ...
- IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(三)
IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(三) 后台服务用户与认证 新建一个空的.net core web项目Demo.Chat,端口配置为 ...
- IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(一)
IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯 前言 .net core 2.1已经正式发布了,signalr core1.0随之发布,是时候写个 ...
- IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(二)
IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(二) IdentityServer4 用户中心生成数据库 上文已经创建了所有的数据库上下文迁移代码 ...
- 搭建一套简单的web服务器,记录实验过程
搭建web服务器 一.实验内容: 实验要求: 1.完成一个简单的web服务器,web服务器从mysql里读取数据进行返回 2.Mysql需要有一个单独的数据盘,每个mysql虚拟机的磁盘挂载方式需要都 ...
- openfire+asmack搭建的安卓即时通讯(三) 15.4.9
(能用得上话的话求点赞=-=,我表达不好的话跟我说哦) 上一次我们拿到了服务器端的组数据和用户信息,这就可以为我们日后使用好友系统打下基础了! 但是光是拿到了这些东西我们怎么能够满足呢?我们一个即时通 ...
- web即时通讯2--基于Spring websocket达到web聊天室
如本文所用,Spring4和websocket要构建web聊天室,根据框架SpringMVC+Spring+Hibernate的Maven项目,后台使用spring websocket进行消息转发和聊 ...
- Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!
本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...
随机推荐
- 源码编译路径错误导致的Apache 无法重启问题解决方法
问题现象: 第一次源码编译安装Apache设置路径错误,安装到/usr/local/src/ 目录下了. 删掉该目录下的安装文件,重新编译安装到/usr/local/目录下 重启apache服务时报这 ...
- Delphi多线程下的ADO编程
前言: 几个月前接到一个任务:将一后台程序访问数据库的方式从BDE改为ADO,原因是由于业务量的增加,通过BDE不论是向数据库写入数据还是从数据库中读出数据的速度都变得无法忍受,大家都知道ADO在数据 ...
- Win8 Metro(C#)数字图像处理--2.43图像马赛克效果算法
原文:Win8 Metro(C#)数字图像处理--2.43图像马赛克效果算法 [函数名称] 图像马赛克效果 MosaicProcess(WriteableBitmap src, i ...
- QString转换为LPTSTR(使用了reinterpret_cast,真是叹为观止,但是也开阔了思路),三篇文章合起来的各种转换方法
醉了,windows下宏定义了很多char类型 LPTSTR .今天,直接使用,qt报错,真TM费事. 将“CPU”转化为wcha_t * QString str = "CPU"; ...
- 十七 bootstrap-table tableExport 导出xlsx格式表格
原文:十七 bootstrap-table tableExport 导出xlsx格式表格 在[十六.bootstrap-table javascript导出数据]中,打开导出的表格时,总会弹出一个提示 ...
- asp.net core2.0中网站发布的时候,视图文件不被打包成dll
项目csproj文件里面加 <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <Target ...
- Redis简介和安装
Redis介绍 Redis是一种Key-Value存储系统(数据库),其提供了一组丰富的数据结构,如List,Sets,Hashes和Ordered Sets Redis安装 wget <Red ...
- 多态与虚拟 : 物件导向的精髓 (侯捷在石器时代对OO的理解)
[自序]虑而後能得(自序)故事接触 C++ 大约是 1989 年的事.那时候的 PC 以现在的眼光看,除了「蛮荒」之外没有更合适的形容词了.横扫千军的 Windows 3.0 还没有诞生,如今以 C+ ...
- Dynamic linking is coming to iOS, tvOS, and watchOS ports of Qt in the 5.9 release
http://blog.qt.io/blog/2017/01/23/qt-5-8-released/ Dynamic linking is coming to iOS, tvOS, and watch ...
- QT_NO_CAST_FROM_ASCII这个宏的,禁用一切来自双引号字符串字面量传入QString(有2种解决方法)
这两天制作了两个Qt Creator增强套装的两个插件,其实也是非常简单的,但是其实花了我超过四天的时间,为什么呢?因为我之前很长一段时间都是在Linux下开发的,一切安好,没有任何问题,但是到了Wi ...