WebSocket + Redis简单快速实现Web网站单设备登录功能

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 单设备登录作用很明显,就是为了保护用户账号安全,今天我们不说手机APP,我们来说说PC Web网站如何简单快速实现这种效果。本篇文章重点是实现单设备登录,内容未涉及WebSocket + Redis的概念和使用方法。限于本人经验,如有错误,欢迎指正。

1、写在前面的话

生活中,我们在使用一些APP的时候,有过一种体验,就是在A手机上登录账号,因为某些原因需要在B手机上登录,然后就会在A手机上看到类似"该账号在其他设备登录"的提示,像下面这样:

image.png

这种方式叫单设备登录,作用很明显,就是为了保护用户账号安全,今天我们不说手机APP,我们来说说PC Web网站如何简单快速实现这种效果。本篇文章重点是实现单设备登录,内容未涉及WebSocket + Redis的概念和使用方法。限于本人经验,如有错误,欢迎指正。

image.png

2、概念

简单的给”单设备登录“定义一下,就是只能在一个设备上登录,若同时在其他设备登录,先前登录的用户会被提醒:该账户在其他设备登录。例如微信,在一台手机登录中,同时拿另一台手机登录该账户,之前那部手机的账户会被挤下线。

image.png

3、思路

使用此方案的前提是要保证登录账号没有重复

在socket里面创建两个Map,sessionPool和sessionIds,分别用来存放客户端会话池和客户端会话标记

用户登录账号成功,进入应用首页,和服务端建立socket连接,将账号+"_"+UUID格式的字符串作为state参数的值

在OnOpen连接时,以state为key,当前session为value存入sessionPool,以sessionId为key,state为value存入sessionIds

以"_"分隔state成数组,取第一个元素即获取到当前登录的账号

在缓存(Redis)里模糊查询含有该账号的key集合,如果存在,那么就取出对应的value值,其实这个value存的就是首先登陆这个账号的那个state,就可以根据这个state给先登录的账号设备推送消息并做logout的操作,并清除缓存

把当前登录的state作为key和value存入缓存,失效时间设置与否都可以,如果设置的话需超过登录态失效的时长

image.png

4、代码实现

这里贴上几段核心代码

后台WebSocket-On0pen,切记如果设置缓存失效时间的话需超过登录态失效的时长

 * 连接时触发
 * @param state
 * @param session
 */
@OnOpen
public void onOpen(@PathParam(value = "state")String state,Session session) {
    this.session = session;
    sessionPool.put(state, session);
    sessionIds.put(session.getId(), state);     
    String[] arry = state.split("_");
    Set<String> keys = redisService.keys(arry[0] + "*");
    if (keys != null) {
        List<String> list = redisService.multiGet(keys);
        for (String value : list) {
            sendMessage("您的账号于"+ DateUtils.pageformat(DateUtils.getCurrentTime()) + "在另一台设备登录,如果这不是您的操作,那么您的登录密码已泄露,请尽快修改",value);
            redisService.delete(value);
        }
    }
    redisService.set(state,state,7200);
}

/**
 * 自定义发送消息的方法
 * @param message
 * @param state
 */
public static void sendMessage(String message,String state) {
    Session session = sessionPool.get(state);
    if (session != null) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

查看缓存

image.png

前端js连接WebSocket方法

return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    var r = Math.random() * 16 | 0,
        v = (c === 'x' ? r : (r & 0x3 | 0x8));
    return v.toString(16);
});
}

function loginSocket(userName) {
var websocket = null;
if ('WebSocket' in window) {
    websocket = new WebSocket("ws://localhost:8080/mobile/socketServer/"+userName+"_"+getUUID());
} else {
    layer.alert('当前浏览器 不支持 websocket')
}
//连接成功建立的回调方法
websocket.onopen = function () {
    console.log('websocket连接成功');
};
//连接发生错误的回调方法
websocket.onerror = function () {
    console.log('websocket连接发生错误');
};
//接收到消息的回调方法
websocket.onmessage = function (event) {
    $.getJSON("logout", function(r){
        console.log('logout:'+event.data);
    });
    layer.confirm(event.data, {
        btn: ['确定'] //按钮
    }, function(){
        location.href = 'login.html';
    });
};
//连接关闭的回调方法
websocket.onclose = function () {
    console.log("websocket连接关闭");
};
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
    websocket.close();
};
}

image.png

5、验证效果

打开谷歌浏览器,账号密码登录

打开火狐浏览器,模拟不同设备,账号密码登录

再看下谷歌浏览器,页面弹窗提示

image.png

点击确定会跳转到登录页,谷歌浏览器的账号已经被挤下线退出应用

谷歌浏览器再次登录,看下火狐浏览器,也弹窗提示,之前登录的账号也被挤下线退出应用

image.png

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海

上一篇:Linux安装Elasticsearch

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
监控 JavaScript 前端开发
《理解 WebSocket:Java Web 开发的实时通信技术》
【4月更文挑战第4天】WebSocket是Java Web实时通信的关键技术,提供双向持久连接,实现低延迟、高效率的实时交互。适用于聊天应用、在线游戏、数据监控和即时通知。开发涉及服务器端实现、客户端连接及数据协议定义,注意安全、错误处理、性能和兼容性。随着实时应用需求增加,WebSocket在Java Web开发中的地位将更加重要。
|
1月前
|
存储 缓存 NoSQL
深入了解Redis键管理:探索Redis键命令及其功能与应用场景
深入了解Redis键管理:探索Redis键命令及其功能与应用场景
|
1月前
|
消息中间件 存储 缓存
探索Redis CLI:功能强大的Redis命令行工具及其应用场景
探索Redis CLI:功能强大的Redis命令行工具及其应用场景
|
2月前
|
存储 缓存 NoSQL
在Python Web开发过程中:数据库与缓存,Redis在Web开发中的常见应用场景有哪些?
Redis在Python Web开发中常用于缓存、会话管理、分布式锁、排行榜、消息队列和实时分析。作为内存数据存储,它提供高效的数据结构(如字符串、哈希、列表、集合、有序集合),支持会话存储、互斥操作、计数与排名、队列实现及实时数据处理。其高速性能和丰富功能使其成为多场景下的理想选择。
26 5
|
12天前
|
缓存 NoSQL Java
【亮剑】分布式锁是保证多服务实例同步的关键机制,常用于互斥访问共享资源、控制访问顺序和系统保护,如何使用注解来实现 Redis 分布式锁的功能?
【4月更文挑战第30天】分布式锁是保证多服务实例同步的关键机制,常用于互斥访问共享资源、控制访问顺序和系统保护。基于 Redis 的分布式锁利用 SETNX 或 SET 命令实现,并考虑自动过期、可重入及原子性以确保可靠性。在 Java Spring Boot 中,可通过 `@EnableCaching`、`@Cacheable` 和 `@CacheEvict` 注解轻松实现 Redis 分布式锁功能。
|
17天前
|
存储 监控 NoSQL
|
17天前
|
存储 NoSQL API
Redis入门到通关之GEO实现附近的人功能
Redis入门到通关之GEO实现附近的人功能
11 0
|
17天前
|
存储 NoSQL Redis
Redis入门到通关之Set实现点赞功能
Redis入门到通关之Set实现点赞功能
15 0
|
1月前
|
存储 NoSQL 数据处理
Redis Lua脚本:赋予Redis更强大的逻辑与功能
Redis Lua脚本:赋予Redis更强大的逻辑与功能
|
2月前
|
缓存 NoSQL Shell
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(持久化功能分析)
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(持久化功能分析)
166 0