web服务,C/S框架,单设备登陆实现方案

背景: 原登陆接口,校验密码通过后,使用springsession记录会话信息,将信息存入在redis中

基于原逻辑进行多设备登陆开发,默认的时候多设备登陆开关开启,即按原来逻辑处理,只要密码登陆校验成功之后,都会将当前的会话信息存入redis中.

当多设备开关关闭时候,同一个账号同一时间只能在一个设备上运行.实现思路如下:

     1.用户每次登录时,前端在header请求头中加入DeviceId字段传给后端,登陆校验成功后,springsession将 `spring:session:sessions:+sessionid`作为key存入到redis中,将deviceId作为属性存入该key中.前端使用的库提示获取的diviceId唯一概率100%,所以加上后端获取的客户端ip+设备的mac地址,计算md5值作为设备唯一id

        而后将userId与sessionId进行映射,即一个userId对应多次登陆会话sessionId.

     2.用户访问的时候,在过滤器解析sessionid,获取userid不为空,则说明有权限访问。如果获取userid为空,则告诉无权限访问,跳转到登录页面。

     3.用户在另一台设备登录时,登陆成功后,根据userId查看对应的sessionId,根据sessionId查找在线中的会话,然后与当前登陆设备的deviceId进行对比

       如果一致则不处理(同设备下该账号可以在其他浏览器登陆),如果不一致,则删除redis缓存中的session会话信息,使之前该账号的登陆会话失效.

探测接口需要注意:

修改原因:

     因为springsession有过期时间,当客户端给服务器发送会话请求的时候,

     他会将该会话的最后活跃时间更新,那么过期时间会等于最后活跃时间加上过期时限,只要有请求一直发送,就一直不会过期.

当前方案:

     现在采用无状态接口,请求的时候不需要判断会话的sessionid(在过滤器已经排除在外),

    请求后判断该会话的sessonid是否失效,将结果返回给前端

springsession提供的API 可以通过属性字段查询当前的用户对应的sessionid,支持分布式

int currentLoginNumber = sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, user.getUserId()).size();

而自己维护的userid->sessionid关系,存储在进程的内存中,可能出现分布式不同客户端的时候数据不一致.逻辑上都是使用userID与SessionId进行关系映射.

代码示例:

// 多设备登陆关闭 只允许同一时间,同一个userId只能在一个设备上登陆
if (!systemServer.getMultipleDeviceLoginSetting()) {
            //当前用户下存活的会话
            Set<String> userIdSessions = sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, user.getUserId()).keySet();
            this.handleMultipleDeviceLoginSetting(userIdSessions);

        }

// 删除存活的SESSIONID
private void handleMultipleDeviceLoginSetting(Set<String> userIdSessions) {
        String SESSION_PREFIX = "spring:session:sessions:";

        if (userIdSessions != null && !userIdSessions.isEmpty()) {
            userIdSessions.forEach(o -> {
                String sessionId = SESSION_PREFIX + o;
                final Object user = sessionRepository.getSessionRedisOperations().opsForHash().get(sessionId, "sessionAttr:UserId");
                if (null != user) {  //用户在线中
                        // 认为该账号在其他设备登陆 需要将该会话强制清除
                        sessionRepository.getSessionRedisOperations().delete(sessionId);
                    }
            });
        }
    }

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值