一套简单的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端即时通讯技术应用场景,主要有以下两种形式 ...
随机推荐
- rc-form(翻译)
原地址:https://npm.taobao.org/package/rc-form rc-form React 高阶表单控制组件. 开发 npm install npm start op ...
- C#使用Selenium实现QQ空间数据抓取 登录QQ空间
经@吃西瓜的星星提醒 首先我们介绍下Selenium Selenium也是一个用于Web应用程序测试的工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE.Mo ...
- WPF数据模板的数据触发器的使用
<Window x:Class="CollectionBinding.MainWindow" xmlns="http://schemas.micros ...
- C# WebClient的使用
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- ORM 集合
1.EF https://github.com/aspnet 2.Chloe.ORM http://www.cnblogs.com/so9527/p/5809089.html http://www ...
- WPF后台生成datatemplate(TreeViewItem例子)
public void loadCheckListDataTemplate(TreeViewItem tvi) { DataTemplate cdt = new DataTemplate(); Fra ...
- c# SQLHelper总汇
/// <summary> /// The SqlHelper class is intended to encapsulate high performance, /// scalabl ...
- Qt打开外部程序和文件夹需要注意的细节(注意QProcess的空格问题,以及打开本地文件时,需要QUrl::fromLocalFile才可以)
下午写程序中遇到几个小细节,需要在这里记录一下. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 QProcess *process = new QProcess(this ...
- Win8 Metro(C#)数字图像处理--2.51图像统计滤波算法
原文:Win8 Metro(C#)数字图像处理--2.51图像统计滤波算法 [函数名称] 图像统计滤波 WriteableBitmap StatisticalFilter(Writeab ...
- shell中特殊变量及if条件
特殊变量: linux中shell变量$#,$@,$,$,$2的含义解释: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? ...