http://blog.sina.com.cn/s/blog_667ac0360102yrg1.html

    多端登录系统需求

    1 多端登录,用户信息只缓存一份;

    2 多端登录,会话超时可以自定义;

    3 多端登录,同一个账号能否支持多人同时登录,可以配置;支持账号异常,再下次登录时候提醒上次登录的IP地址,注意修改密码;

    4 支持服务器重启不影响客户端的会话保持,下次操作也不会要求重新登录;

    5 登录会话可以清楚显示当前用户有几个客户端在线,这些在线用户访问的是哪个系统,系统版本,APP版本;

    6 多端的分类是按照客户端类型,浏览器、APP、微信、微信小程序来分类;而且还能细分到所登录的系统是哪个;比如:账号A,会话有3个,其中这3个会话有可能所登录的系统是不同的;

    注意:当不允许多人同时登录的时候,一个账号是否进行了多人同时登录的判断是:用户ID+客户端平台+系统ID;

    7 支持多业务系统、多客户端,多会话配置,统一登录;系统缓存的用户信息仅存储一份;

    用户表——User

    Integer id; // ID

    Integer perId; // 人员ID

    String username; // 账号

    String password; // 密码(加密)

    Integer status; // 状态 0 注册未激活 1 正常已激活 -1 账号锁定

    String salt; // “盐”

    String head; // 头像

    Date createTime; // 创建时间

    Date updateTime; // 更新时间

    // 服务器重启后,不需要客户端重新登录;服务端使用内存、数据库两级存储,当缓存找不到,则从数据库找并且刷新缓存;

    用户会话表——UserSession(与登录用户的内存对象一一映射)

    Integer uid; // 用户ID(主键)

    String username; // 用户账号

    Date createTime; // 创建时间

    Date updateTime; // 更新时间

    用户会话明细表——UserSessionDetail

    String uuid; // 会话ID

    String ip; // 登录IP地址

    Integer expireAt; // 超时时间(秒)

    Integer appSys; // 所属应用系统

    String uid; // 用户ID

    String ver; // APP版本号 或者 H5资源版本号

    Date createTime; // 创建时间

    Date updateTime; // 更新时间

    系统日志(登录日志、重要操作日志)——SystemLog

    Integer id; // ID

    Integer appSysId; // 属于哪个应用系统

    Integer userId; // 用户ID

    String username; // 用户名

    String type; // LOGIN 登录日志,ACTION 操作日志;

    String operation; // 操作内容

    String ip; // 登录IP

    String addr; // 登录地区

    String loginPlatform; // 多端区分

    String appPackage; // app包名

    Date createTime; // 创建时间

    Date updateTime; // 更新时间

    后端系统用户缓存结构

    _usContext用户会话上下文,与数据库保持同步;

    key:uid, value:userSessionObj

    _uuidContext

    key: uuid, value: userSessionObj;value指向_usContext的userSessionObj;

    系统配置

    1 多端登录配置

    {

    “remind”: true,

    “platforms”: [

    {“name”: “browser”, “multiLogin”: true, “maxAge”:1800},

    {“name”: “app”, “multiLogin”: false, “maxAge”:31536000},

    {“name”: “wxgzh”, “multiLogin”: false, “maxAge”:31536000},

    {“name”: “wxapp”, “multiLogin”: false, “maxAge”:31536000}]

    }

    说明

    multiLogin:是否允许多人同时登录;

    maxAge:会话超时时间;

    2 不允许多人同时登录,是否需要提醒用户

    login_remind=true // true要通知、false不通知;

    不允许多人同时登录的规则

    每次登录时候,检测当前平台是否允许多人同时登录;若不允许,则检测该用户是否有人已经登录过了;若已经有人登录过了,也就是多人同时登录了,后面登录的人会覆盖前面登录的人;前面登录的人下次请求时候会下线;

    若login_remind=true,则前面登录的人,下次再登录的时候会给出风险提示,提示上次登录的IP、地区;

    用户会话操作

    1 新增

    1)UserSession对象持久到数据库;

    若不存在,则插入;若存在,则更新时间;

    2)UserSessionDetail对象持久到数据库(包含最后一次操作时间);

    若允许多端登录,则插入明细;

    若不允许多端登录,则根据uid、platform、appsys查询是否有人登录过;若登录过,则覆盖前面人的uuid;否则,插入明细;

    3)刷新缓存

    数据库操作完毕后,查询最新的UserSession(不存在最后一次操作时间);

    将最后一次操作时间,重新写入到UserSessionDetail;数据库并没有存最后一次操作时间,是存在与内存的;

    将最新的UserSession放入_usContext、_uuidContext;

    2 删除

    1)获取数据

    根据request获取uuid,根据uuid从_uuidContext获取UserSession,然后获取uid;

    2)删除数据库

    根据uuid从数据库删除会话明细UserSessionDetail;若该用户的会话明细都删完了,则把会话信息UserSession删除;否则,更新UserSession的updateTime更新时间;

    3)删除缓存

    根据uuid从缓存_uuidContext删除;

    根据uid从数据库加载UserSession,若存在,则刷新;若不存在,则从缓存_usContext移除;

    3 查询

    1)获取数据

    根据request获取uuid,根据uuid获取UserSession;

    若UserSession!=null,则直接返回;否则,如下处理:

    从数据库加载UserSession;若存在,刷新缓存,明细需要写入最后操作时间为当前时间(明细的最后操作时间没有写入数据库,因为是为了避免频繁更新当前用户的最后操作时间);若不存在,则返回null;

    注意:新增、删除、查询时候从数据库加载数据的时候,这些操作都需要线程同步;

    登录操作

    1) 验证账号、密码正确;

    2)根据request获取platform、appSys、ip,从配置文件获取isMultiLogin、maxAge,生成uuid;

    3)创建会话信息UserSession以及UserSessionDetail,并调用上方的用户会话的新增操作;

    4)设置cookie

    设置uuid、platform到cookie,超时时间就是maxAge;

    5)返回登录成功;

    退出操作

    1)调用上面定义的用户会话清除操作

    2)删除cookie

    删除uuid、platform;

    3)重定位到登录页面

    登录拦截器

    根据request,调用上面的获取UserSession操作

    若存在,则验证是否会话是否超时;若超时,则返回账号超时(ajax)、重定位到登录页(html);若未超时,则继续执行;

    若不存在,则返回账号超时(ajax)、重定位到登录页(html);

    参考

    多端登录系统分析

    多端登录demo测试