一套简单的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端即时通讯技术应用场景,主要有以下两种形式 ...
随机推荐
- WebService它Soap头验证进入
1.创建一个新的类.如"AuthHeaderUser",在传承"System.Web.Services.Protocols.SoapHeader"类别 2.新W ...
- POJ3723 Conscription 【并检查集合】
Conscription Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8071 Accepted: 2810 Desc ...
- Matlab随笔之判别分析
原文:Matlab随笔之判别分析 从概率论角度,判别分析是根据所给样本数据,对所给的未分类数据进行分类. 如下表,已知有t个样本数据,每个数据关于n个量化特征有一个值,又已知该样本数据的分类,据此,求 ...
- WPF特效-鱼游动动画
原文:WPF特效-鱼游动动画 实现思路: 通过VisualBrush Binding方式获取鱼局部图像,在Viewport3D中创建ModelVisual3D块并把获取到的局部 ...
- 解压压缩文件报错gzip: stdin: not in gzip format tar: Child returned status 1 tar: Error is not recoverable: exiting now
压缩包是直接weget 后面加官网上的tar包地址获取的 [root@xuegod43 ~]# tar -zxvf /home/hadoop/hadoop-2.6.5-src.tar.gz gzip ...
- QWidget继承自QPaintDevice,这样就可以直接把QWidget传入QPainter的构造函数,比如QPainter(mylabel),然后设置QWidget的长宽后直接进行作画了
比如用QLabel在主界面上画两条虚线: bool ContentWidget::eventFilter(QObject *obj, QEvent *event) { if(obj == line_l ...
- Lexer的设计--上(3)
lexer的构造函数 有了上一节Token做铺垫, 可以开始设计lexer, 首先应该想到的是, 源代码是以文件流的格式传到编译器中的, 所以作为编译器的前段的第一个阶段, lexer必须负责处理输入 ...
- WPF中类似使用tab键功能,可以向上向下定位
原文:WPF中类似使用tab键功能,可以向上向下定位 private void tbYyrs_KeyUp(object sender, KeyEventArgs e) { UIElement elem ...
- WPF应用App.Config文件的保存路径
App.Config文件有更改后,自动会保存到以下路径: C:\Users\你的系统用户名\AppData\Local\你的应用名\
- WPF与WinForm的抉择
微软曾经对WPF(代号Avalon)抱很大的期望——新一代的华丽用户界面平台,一统Web应用和桌面应用,Flash杀手,尽管微软口头上不承认.几年下来,WPF确实实现了当初的预期的大部分功能,但离称霸 ...