• 使用 Sa-Token 实现不同的登录模式:单地登录、多地登录、同端互斥登录


    一、需求分析

    如果你经常使用腾讯QQ,就会发现它的登录有如下特点:它可以手机电脑同时在线,但是不能在两个手机上同时登录一个账号。

    同端互斥登录,指的就是:像腾讯QQ一样,在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线。

    动态演示图:

    同端互斥登录

    Sa-Token 是一个轻量级 java 权限认证框架,主要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。
    Gitee 开源地址:https://gitee.com/dromara/sa-token

    本文将介绍在 Sa-Token 中,如何实现以下登录策略:

    • 单地登录:指一个账号同一时间只能在一个地方登录,新登录会挤掉旧登录,也可以叫:单端登录。
    • 多地登录:指一个账号同一时间可以在不同地方登录,新登录会和旧登录共存,也可以叫:多端登录。
    • 同端互斥登录:在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线,参考腾讯QQ的登录模式:手机和电脑可以同时在线,但不能两个手机同时在线。

    与之对应的,注销策略也将分为以下几种:

    • 单端注销:只在调用退出的一端注销。
    • 全端注销:一端注销,全端下线。
    • 同端注销:例如将所有手机端注销下线,PC端不受影响。

    二、多地登录

    此模式较为简单,Sa-Token 默认模式即为多地登录模式。

    1、首先引入 Sa-Token 依赖:
    
    <dependency>
    	<groupId>cn.dev33groupId>
    	<artifactId>sa-token-spring-boot-starterartifactId>
    	<version>1.34.0version>
    dependency>
    

    注:如果你使用的是 SpringBoot 3.x,只需要将 sa-token-spring-boot-starter 修改为 sa-token-spring-boot3-starter 即可。

    2、在用户登录时将账号id写入会话中
    @RestController
    @RequestMapping("/user/")
    public class UserController {
    	@RequestMapping("doLogin")
    	public SaResult doLogin(String username, String password) {
    		// 此处仅作示例模拟,真实项目需要从数据库中查询数据进行比对 
    		if("zhang".equals(username) && "123456".equals(password)) {
    			StpUtil.login(10001);
    			return SaResult.ok("登录成功");
    		}
    		return SaResult.ok("登录失败");
    	}
    }
    

    启动类:

    @SpringBootApplication
    public class SaTokenDemoApplication {
    	public static void main(String[] args) {
    		SpringApplication.run(SaTokenDemoApplication.class, args); 
    		System.out.println("\n启动成功:Sa-Roken 配置如下:" + SaManager.getConfig());
    	}
    }
    

    如上代码,在多人登录同一账号时将不会对旧会话做任何处理,同一账号可以在多个地点任意登录,互不影响。

    3、如果要全端注销,可以调用 logout 方法:
    // 会话注销
    @RequestMapping("logout")
    public SaResult logout() {
    	StpUtil.logout();
    	return SaResult.ok("退出登录成功");
    }
    

    调用如上方法注销后,当前账号所有端将一起下线。

    4、单端注销

    如果要只注销一端,可将配置文件中 is-share 的值配置为 false

    sa-token:
    	is-share: false
    

    此配置项的含义为:在多人登录同一账号时,是否共用一个 Token。

    • 为 true 时:所有登录共用一个 Token。
    • 为 false 时:每次登录新建一个 Token。

    此值为 false 后,每次登录都将返回不同的 Token,与之对应的,调用 StpUtil.logout() 也只会注销掉当前的 Token,其他端不受影响。

    三、单地登录

    单地登录的重点是需要改一下 yml 配置文件:

    sa-token: 
    	is-concurrent: false
    

    is-concurrent 的含义为是否允许同一账号并发登录:

    • 为 true 时:允许一起登录。
    • 为 false 时:新登录挤掉旧登录。

    其它代码与 [多地登录] 无异,当我们在两个浏览器分别登录同一账号时,旧会话再次访问系统将会得到如下提示:

    {
    	"code": 401,
    	"msg": "Token 已被顶下线",
    	"data": null
    }
    

    在 单地登录 模式中,不存在注销策略的问题,因为同一时间内,一个账号最多在一个设备在线,只要调用注销,就必然是全端下线。

    四、同端互斥登录

    好了,终于轮到主角出场,同端互斥登录可以让我们像腾讯QQ一样,在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线。

    那么在 Sa-Token 中如何做到同端互斥登录呢?

    首先如 单地登录一样,在配置文件中,将 sa-token.is-concurrent 配置为false,然后调用登录等相关接口时声明设备标识即可:

    1、指定设备标识登录
    StpUtil.login(10001, "PC");    
    

    调用此方法登录后,同设备的会被顶下线(不同设备不受影响),再次访问系统时会抛出 NotLoginException 异常,场景值=-4

    场景值 对应常量 含义说明
    -1 NotLoginException.NOT_TOKEN 未能从请求中读取到 Token
    -2 NotLoginException.INVALID_TOKEN 已读取到 Token,但是 Token无效
    -3 NotLoginException.TOKEN_TIMEOUT 已读取到 Token,但是 Token已经过期
    -4 NotLoginException.BE_REPLACED 已读取到 Token,但是 Token 已被顶下线
    -5 NotLoginException.KICK_OUT 已读取到 Token,但是 Token 已被踢下线

    如果第二个参数填写null或不填,代表将这个账号id所有在线端踢下线,被踢出者再次访问系统时会抛出 NotLoginException 异常,场景值=-5

    2、查询当前登录的设备标识
    StpUtil.getLoginDevice(); 
    

    如果在登录时未指定设备类型值,调用此方法将返回默认值:default-device

    3、指定设备端类型下线

    业务场景举例:在手机端控制PC端下线(手机端本身不受影响)

    StpUtil.logout(10001, "PC");		
    
    4、全端下线

    在调用 logout 方法时,不填写具体的设备端类型,将默认控制所有端一起下线。

    StpUtil.logout(10001);		
    

    以上就是 Sa-Token 框架在处理登录问题时的各种方案,可以看出不管是简单的多地登录还是复杂的同端互斥登录,在 Sa-Token 都有完善的解决方案。


    参考资料

  • 相关阅读:
    yakit的web fuzzer功能的使用
    K8S控制器
    客户案例 | 聚焦流程体验,助银行企业APP迭代
    零基础CMake入门(基于ROS)
    点云从入门到精通技术详解100篇-基于点云数据的工件三维重建
    我们为什么需要 DAO 操作系统?
    任务兼职系统开发
    【WEEK15】 【DAY2】【DAY3】邮件任务【中文版】
    初识Cpp之 三、Cpp预处理器
    MySQL数据库如何线上修改表结构
  • 原文地址:https://www.cnblogs.com/shengzhang/p/17539823.html