ParcelS实现单点登录

2020年11月23日 作者 胡凯

一、业务场景

场景一:用户1(非IT)使用账号A登录系统后,用户2(非IT)再登录账号A,则会将用户1登录的账号踢下线,系统并弹窗提示;
场景二:用户1(非IT)使用账号A登录系统后,用户2(IT)再登录账号A,不会将用户1踢下线;
场景三:用户1(IT)使用账号A登录系统后,用户2(非IT)再登录账号A,不会将用户1踢下线;
场景四:用户1(IT)使用账号A登录系统后,用户2(IT)再登录账号A,不会将用户1踢下线。

二、解决方案

方案1:在旧的session设置值,isLogin方法中获取当前登录session是否有设置过属性值,有则退出当前账号。

实现步骤:
  1. 登录时,通过获取redis中是否有记录过该用户的sessionId判断账号是否已经被登录过;
  2. 如果当前账号已经登录,则获取旧的session,并设置属性标记(如:“keckout”, ture);
  3. 系统调用isLogin接口时,获取当前登录的session,查看是否有设置过属性标记,有则将当前登录的账号踢下线。
业务流程:

优点:简单直接,主要针对session做事情
缺点:未找到比较好的方法来获取旧的session

方案2:登录时如果发现账号已被登录,直接删除该session

实现步骤:
  1. 登录时,通过获取redis中是否有记录过该用户的sessionId判断账号是否已经被登录过;
  2. 如果当前账号已经登录,直接将对应的session删掉;
  3. 系统调用isLogin接口时,当检测到session没有了则直接退出。
业务流程:

缺点:当被踢出时候无法在页面返回正确的消息提示(为何掉线了?)

方案3:将上一次登录的sessionId存到redis中

实现步骤:
  1. 登录时,通过获取redis中是否有记录过该用户的sessionId判断账号是否已经被登录过;
  2. 如果当前账号已经登录,把登录过的sessionId存入到redis中;
  3. 系统调用isLogin接口时,获取当前登录的sessionId,并且从redis中取当前user的sessionId,如果不一致,则将其踢出。
业务流程:

缺点:并发登录时候由于只记住了最后一次的sessionId,所以不能将已登录的完全踢出去

方案4:只要不是最后登录sessionId的,都自动退出

实现步骤:
  1. 登录时,通过获取redis中是否有记录过该用户的sessionId判断账号是否已经被登录过;
  2. 如果当前账号已经登录,把当前登录的sessionId存入到redis;
  3. 系统调用isLogin接口时,当检测到当前登录用户的sessionId不等于redis中存的userId对应的sessionId时则直接退出。
业务流程:

三、功能完善

针对IT登录(使用admin的密码登录账号)时候,应该和员工用自己登录账号互不干扰,保证互相不会被踢下线。
实现流程:

四、相关业务代码

shiro登录成功的回调

初始化session

存入sessionId到redis

sessionId和明文密码存入到redis

isLogin接口