如果你经常使用腾讯QQ,就会发现它的登录有如下特点:它可以手机电脑同时在线,但是不能在两个手机上同时登录一个账号。
同端互斥登录,指的就是:像腾讯QQ一样,在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线。
动态演示图:
Sa-Token 是一个轻量级 java 权限认证框架,主要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。
Gitee 开源地址:https://gitee.com/dromara/sa-token
本文将介绍在 Sa-Token 中,如何实现以下登录策略:
与之对应的,注销策略也将分为以下几种:
此模式较为简单,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
即可。
@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());
}
}
如上代码,在多人登录同一账号时将不会对旧会话做任何处理,同一账号可以在多个地点任意登录,互不影响。
logout
方法:// 会话注销
@RequestMapping("logout")
public SaResult logout() {
StpUtil.logout();
return SaResult.ok("退出登录成功");
}
调用如上方法注销后,当前账号所有端将一起下线。
如果要只注销一端,可将配置文件中 is-share
的值配置为 false
sa-token:
is-share: false
此配置项的含义为:在多人登录同一账号时,是否共用一个 Token。
此值为 false 后,每次登录都将返回不同的 Token,与之对应的,调用 StpUtil.logout()
也只会注销掉当前的 Token,其他端不受影响。
单地登录的重点是需要改一下 yml 配置文件:
sa-token:
is-concurrent: false
is-concurrent
的含义为是否允许同一账号并发登录:
其它代码与 [多地登录] 无异,当我们在两个浏览器分别登录同一账号时,旧会话再次访问系统将会得到如下提示:
{
"code": 401,
"msg": "Token 已被顶下线",
"data": null
}
在 单地登录 模式中,不存在注销策略的问题,因为同一时间内,一个账号最多在一个设备在线,只要调用注销,就必然是全端下线。
好了,终于轮到主角出场,同端互斥登录可以让我们像腾讯QQ
一样,在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线。
那么在 Sa-Token 中如何做到同端互斥登录呢?
首先如 单地登录
一样,在配置文件中,将 sa-token.is-concurrent
配置为false
,然后调用登录等相关接口时声明设备标识即可:
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
StpUtil.getLoginDevice();
如果在登录时未指定设备类型值,调用此方法将返回默认值:default-device
。
业务场景举例:在手机端控制PC端下线(手机端本身不受影响)
StpUtil.logout(10001, "PC");
在调用 logout
方法时,不填写具体的设备端类型,将默认控制所有端一起下线。
StpUtil.logout(10001);
以上就是 Sa-Token 框架在处理登录问题时的各种方案,可以看出不管是简单的多地登录还是复杂的同端互斥登录,在 Sa-Token 都有完善的解决方案。