mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-04-05 17:37:53 +08:00
新增身份临时切换功能
This commit is contained in:
parent
c7f3b6d493
commit
4bfad95bad
sa-token-core/src/main/java/cn/dev33/satoken
sa-token-demo-springboot/src/main/java/com/pj
sa-token-doc/doc/use
sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor
@ -0,0 +1,15 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
/**
|
||||
* 模拟身份方法的辅助类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaFunction {
|
||||
|
||||
/**
|
||||
* 执行的方法
|
||||
*/
|
||||
public void run();
|
||||
|
||||
}
|
@ -44,6 +44,24 @@ public class StpLogic {
|
||||
this.loginKey = loginKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
*/
|
||||
public String getLoginKey(){
|
||||
return loginKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入当前StpLogin的loginKey
|
||||
* @param loginKey loginKey
|
||||
* @return 对象自身
|
||||
*/
|
||||
public StpLogic setLoginKey(String loginKey){
|
||||
this.loginKey = loginKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// =================== 获取token 相关 ===================
|
||||
|
||||
@ -77,8 +95,8 @@ public class StpLogic {
|
||||
String tokenValue = null;
|
||||
|
||||
// 1. 尝试从request里读取
|
||||
if(request.getAttribute(SaTokenConsts.JUST_CREATED_SAVE_KEY) != null) {
|
||||
tokenValue = String.valueOf(request.getAttribute(SaTokenConsts.JUST_CREATED_SAVE_KEY));
|
||||
if(request.getAttribute(getJustCreatedSaveKey()) != null) {
|
||||
tokenValue = String.valueOf(request.getAttribute(getJustCreatedSaveKey()));
|
||||
}
|
||||
// 2. 尝试从请求体里面读取
|
||||
if(tokenValue == null && config.getIsReadBody() == true){
|
||||
@ -100,14 +118,6 @@ public class StpLogic {
|
||||
return tokenValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
*/
|
||||
public String getLoginKey(){
|
||||
return loginKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的token信息
|
||||
* @return token信息
|
||||
@ -191,7 +201,7 @@ public class StpLogic {
|
||||
|
||||
// ------ 4. 持久化其它数据
|
||||
dao.setValue(getKeyTokenValue(tokenValue), String.valueOf(loginId), config.getTimeout()); // token -> uid
|
||||
request.setAttribute(SaTokenConsts.JUST_CREATED_SAVE_KEY, tokenValue); // 将token保存到本次request里
|
||||
request.setAttribute(getJustCreatedSaveKey(), tokenValue); // 将token保存到本次request里
|
||||
setLastActivityToNow(tokenValue); // 写入 [最后操作时间]
|
||||
if(config.getIsReadCookie() == true){ // cookie注入
|
||||
SaTokenManager.getSaTokenCookie().addCookie(SaTokenManager.getSaTokenServlet().getResponse(), getTokenName(), tokenValue, "/", (int)config.getTimeout());
|
||||
@ -303,6 +313,10 @@ public class StpLogic {
|
||||
* @return 账号id
|
||||
*/
|
||||
public Object getLoginId() {
|
||||
// 如果正在[临时身份切换]
|
||||
if(isSwitch()) {
|
||||
return getSwitchLoginId();
|
||||
}
|
||||
// 如果获取不到token,则抛出:无token
|
||||
String tokenValue = getTokenValue();
|
||||
if(tokenValue == null) {
|
||||
@ -363,6 +377,10 @@ public class StpLogic {
|
||||
* @return 账号id
|
||||
*/
|
||||
public Object getLoginIdDefaultNull() {
|
||||
// 如果正在[临时身份切换]
|
||||
if(isSwitch()) {
|
||||
return getSwitchLoginId();
|
||||
}
|
||||
// 如果连token都是空的,则直接返回
|
||||
String tokenValue = getTokenValue();
|
||||
if(tokenValue == null) {
|
||||
@ -536,7 +554,7 @@ public class StpLogic {
|
||||
if(tokenValue == null || Objects.equals(tokenValue, "")) {
|
||||
// 随机一个token送给ta
|
||||
tokenValue = createTokenValue(null);
|
||||
SaTokenManager.getSaTokenServlet().getRequest().setAttribute(SaTokenConsts.JUST_CREATED_SAVE_KEY, tokenValue);
|
||||
SaTokenManager.getSaTokenServlet().getRequest().setAttribute(getJustCreatedSaveKey(), tokenValue);
|
||||
setLastActivityToNow(tokenValue); // 写入 [最后操作时间]
|
||||
if(getConfig().getIsReadCookie() == true){ // cookie注入
|
||||
SaTokenManager.getSaTokenCookie().addCookie(SaTokenManager.getSaTokenServlet().getResponse(), getTokenName(), tokenValue, "/", (int)getConfig().getTimeout());
|
||||
@ -1039,6 +1057,20 @@ public class StpLogic {
|
||||
return getConfig().getTokenName() + ":" + loginKey + ":last-activity:" + tokenValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在进行身份切换时,使用的存储key
|
||||
*/
|
||||
public String getKeySwitch() {
|
||||
return SaTokenConsts.SWITCH_TO_SAVE_KEY + getLoginKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果token为本次请求新创建的,则以此字符串为key存储在当前request中
|
||||
*/
|
||||
public String getJustCreatedSaveKey() {
|
||||
return SaTokenConsts.JUST_CREATED_SAVE_KEY + getLoginKey();
|
||||
}
|
||||
|
||||
|
||||
// =================== Bean对象代理 ===================
|
||||
|
||||
@ -1052,7 +1084,7 @@ public class StpLogic {
|
||||
}
|
||||
|
||||
|
||||
// =================== 注解鉴权 ===================
|
||||
// =================== 其它方法 ===================
|
||||
|
||||
/**
|
||||
* 对一个Method对象进行注解检查(注解鉴权内部实现)
|
||||
@ -1111,6 +1143,55 @@ public class StpLogic {
|
||||
|
||||
// 验证通过
|
||||
}
|
||||
|
||||
|
||||
// =================== 身份切换 ===================
|
||||
|
||||
/**
|
||||
* 临时切换身份为指定loginId
|
||||
* @param loginId 指定loginId
|
||||
*/
|
||||
public void switchTo(Object loginId) {
|
||||
SaTokenManager.getSaTokenServlet().getRequest().setAttribute(getKeySwitch(), loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束临时切换身份
|
||||
*/
|
||||
public void endSwitch() {
|
||||
SaTokenManager.getSaTokenServlet().getRequest().removeAttribute(getKeySwitch());
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前是否正处于[身份临时切换]中
|
||||
*/
|
||||
public boolean isSwitch() {
|
||||
return SaTokenManager.getSaTokenServlet().getRequest().getAttribute(getKeySwitch()) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回[身份临时切换]的loginId
|
||||
*/
|
||||
public Object getSwitchLoginId() {
|
||||
return SaTokenManager.getSaTokenServlet().getRequest().getAttribute(getKeySwitch());
|
||||
}
|
||||
|
||||
/**
|
||||
* 在一个代码段里方法内,临时切换身份为指定loginId
|
||||
* @param loginId 指定loginId
|
||||
*/
|
||||
public void switchTo(Object loginId, SaFunction function) {
|
||||
try {
|
||||
switchTo(loginId);
|
||||
function.run();
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
} finally {
|
||||
endSwitch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -14,7 +14,16 @@ public class StpUtil {
|
||||
* 底层的 StpLogic 对象
|
||||
*/
|
||||
public static StpLogic stpLogic = new StpLogic("login");
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
*/
|
||||
public static String getLoginKey(){
|
||||
return stpLogic.getLoginKey();
|
||||
}
|
||||
|
||||
|
||||
// =================== 获取token 相关 ===================
|
||||
|
||||
@ -34,14 +43,6 @@ public class StpUtil {
|
||||
return stpLogic.getTokenValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
*/
|
||||
public static String getLoginKey(){
|
||||
return stpLogic.getLoginKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的token信息
|
||||
* @return token信息
|
||||
@ -486,4 +487,37 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
|
||||
// =================== 身份切换 ===================
|
||||
|
||||
/**
|
||||
* 临时切换身份为指定loginId
|
||||
* @param loginId 指定loginId
|
||||
*/
|
||||
public static void switchTo(Object loginId) {
|
||||
stpLogic.switchTo(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束临时切换身份
|
||||
*/
|
||||
public static void endSwitch() {
|
||||
stpLogic.endSwitch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前是否正处于[身份临时切换]中
|
||||
*/
|
||||
public static boolean isSwitch() {
|
||||
return stpLogic.isSwitch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在一个代码段里方法内,临时切换身份为指定loginId
|
||||
* @param loginId 指定loginId
|
||||
*/
|
||||
public static void switchTo(Object loginId, SaFunction function) {
|
||||
stpLogic.switchTo(loginId, function);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ public class SaTokenConsts {
|
||||
public static final String GITHUB_URL = "https://github.com/click33/sa-token";
|
||||
|
||||
/**
|
||||
* 如果token为本次请求新创建的,则以此字符串为key存储在当前request中 JUST_CREATED_SAVE_KEY
|
||||
* 如果token为本次请求新创建的,则以此字符串为key存储在当前request中
|
||||
*/
|
||||
public static final String JUST_CREATED_SAVE_KEY = "JUST_CREATED_SAVE_KEY_";
|
||||
|
||||
@ -32,11 +32,10 @@ public class SaTokenConsts {
|
||||
*/
|
||||
public static final String DEFAULT_LOGIN_DEVICE = "default-device";
|
||||
|
||||
// /**
|
||||
// * 在用一个字符串存储多个token时,所使用的分隔符
|
||||
// */
|
||||
// public static final String MULTIPLE_TOKEN_SEPARATOR = ",";
|
||||
|
||||
/**
|
||||
* 在进行临时身份切换时使用的key
|
||||
*/
|
||||
public static final String SWITCH_TO_SAVE_KEY = "SWITCH_TO_SAVE_KEY_";
|
||||
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@ public class SaTokenDemoApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args);
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaTokenManager.getConfig());
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -145,7 +145,6 @@ public class TestController {
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
|
||||
// 打印当前token信息, 浏览器访问: http://localhost:8081/test/tokenInfo
|
||||
@RequestMapping("tokenInfo")
|
||||
public AjaxJson tokenInfo() {
|
||||
@ -203,6 +202,18 @@ public class TestController {
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试身份临时切换: http://localhost:8081/test/switchTo
|
||||
@RequestMapping("switchTo")
|
||||
public AjaxJson switchTo() {
|
||||
System.out.println("当前会话身份:" + StpUtil.getLoginIdDefaultNull());
|
||||
System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch());
|
||||
StpUtil.switchTo(10044, () -> {
|
||||
System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch());
|
||||
System.out.println("当前会话身份已被切换为:" + StpUtil.getLoginId());
|
||||
});
|
||||
System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch());
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试会话治理 浏览器访问: http://localhost:8081/test/search
|
||||
@RequestMapping("search")
|
||||
|
@ -1,6 +1,7 @@
|
||||
# 模拟他人
|
||||
---
|
||||
|
||||
|
||||
- 以上介绍的api都是操作当前账号,对当前账号进行各种鉴权操作,你可能会问,我能不能对别的账号进行一些操作?
|
||||
- 比如:查看账号`10001`有无某个权限码、获取id账号为`10002`的用户`session`,等等...
|
||||
- `sa-token`在api设计时充分考虑了这一点,暴露出多个api进行此类操作
|
||||
@ -8,23 +9,47 @@
|
||||
|
||||
## 有关操作其它账号的api
|
||||
|
||||
#### StpUtil.getTokenValueByLoginId(Object loginId)
|
||||
- 获取指定`loginId`的`tokenValue`值
|
||||
|
||||
#### StpUtil.logoutByLoginId(Object loginId)
|
||||
- 指定`loginId`的会话注销登录(踢人下线)
|
||||
|
||||
#### StpUtil.getSessionByLoginId(Object loginId)
|
||||
- 获取指定`loginId`的`session`(如果此id尚未创建`session`, 则返回`null`)
|
||||
- 类似API还有:
|
||||
- `StpUtil.getSessionByLoginId(Object loginId, boolean isCreate)` 获取当前会话登录id, `isCreate`代表指定是否在无`session`的情况下新建并返回
|
||||
|
||||
#### StpUtil.hasRole(Object loginId, String role)
|
||||
- 指定`loginId`是否含有指定角色
|
||||
|
||||
#### StpUtil.hasPermission(Object loginId, String permission)
|
||||
- 指定`loginId`是否含有指定权限
|
||||
``` java
|
||||
StpUtil.getTokenValueByLoginId(10001); // 获取指定账号10001的`tokenValue`值
|
||||
StpUtil.logoutByLoginId(10001); // 将账号10001的会话注销登录(踢人下线)
|
||||
StpUtil.getSessionByLoginId(10001); // 获取账号10001的Session对象, 如果session尚未创建, 则新建并返回
|
||||
StpUtil.getSessionByLoginId(10001, false); // 获取账号10001的Session对象, 如果session尚未创建, 则返回null
|
||||
StpUtil.hasRole(10001, false); // 获取账号10001是否含有指定角色标识
|
||||
StpUtil.hasPermission(10001, false); // 获取账号10001是否含有指定权限码
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 临时身份切换
|
||||
|
||||
有时候,我们需要直接将当前会话的身份切换为其它账号,比如:
|
||||
``` java
|
||||
StpUtil.switchTo(10044); // 将当前会话身份临时切换为其它账号
|
||||
StpUtil.getLoginId(); // 此时再调用此方法会返回 10044
|
||||
StpUtil.endSwitch(); // 结束 [身份临时切换]
|
||||
```
|
||||
|
||||
你还可以: 直接在一个代码段里方法内,临时切换身份为指定loginId (此方式无需手动调用`StpUtil.endSwitch()`关闭身份切换)
|
||||
``` java
|
||||
System.out.println("------- [身份临时切换]调用开始...");
|
||||
StpUtil.switchTo(10044, new SaFunction() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch());
|
||||
System.out.println("获取当前登录账号id: " + StpUtil.getLoginId());
|
||||
}
|
||||
});
|
||||
System.out.println("------- [身份临时切换]调用结束...");
|
||||
```
|
||||
|
||||
如果你使用的JDK版本是1.8或以上,上面这一坨可以简写为以下形式:
|
||||
``` java
|
||||
System.out.println("------- [身份临时切换]调用开始...");
|
||||
StpUtil.switchTo(10044, () -> {
|
||||
System.out.println("是否正在身份临时切换中: " + StpUtil.isSwitch());
|
||||
System.out.println("获取当前登录账号id: " + StpUtil.getLoginId());
|
||||
});
|
||||
System.out.println("------- [身份临时切换]调用结束...");
|
||||
```
|
||||
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class MySaTokenConfig implements WebMvcConfigurer {
|
||||
registry.addInterceptor(SaRouteInterceptor.createPermissionVal("user:add", "user:deelete")).addPathPatterns("/UserController/**");
|
||||
|
||||
// 注册一个自定义认证拦截器 (可以写任意认证代码)
|
||||
registry.addInterceptor(new SaRouteInterceptor(new SaFunction() {
|
||||
registry.addInterceptor(new SaRouteInterceptor(new SaRouteFunction() {
|
||||
@Override
|
||||
public void run(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
// 你可以在这里写任意认证代码, 例如: StpUtil.checkLogin();
|
||||
@ -52,7 +52,7 @@ public class MySaTokenConfig implements WebMvcConfigurer {
|
||||
}
|
||||
})).addPathPatterns("/**");
|
||||
|
||||
/** ------ 如果你使用的JDK版本是1.8或以上,上面那一坨可以简写为以下形式 ------ */
|
||||
/** ------ 如果你使用的JDK版本是1.8或以上,上面这一坨可以简写为以下形式 ------ */
|
||||
|
||||
// 注册一个自定义认证拦截器 (可以写任意认证代码)
|
||||
registry.addInterceptor(new SaRouteInterceptor((request, response, handler)->{
|
||||
@ -66,7 +66,7 @@ public class MySaTokenConfig implements WebMvcConfigurer {
|
||||
(你不必像上面的示例一样注册所有拦截器,只要按需注册即可 )
|
||||
|
||||
|
||||
## 3、所有拦截器示例
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaFunction {
|
||||
public interface SaRouteFunction {
|
||||
|
||||
/**
|
||||
* 执行验证的方法
|
@ -41,7 +41,7 @@ public class SaRouteInterceptor implements HandlerInterceptor {
|
||||
/**
|
||||
* 自定义模式下的执行函数
|
||||
*/
|
||||
private SaFunction function;
|
||||
private SaRouteFunction function;
|
||||
|
||||
|
||||
/**
|
||||
@ -131,14 +131,14 @@ public class SaRouteInterceptor implements HandlerInterceptor {
|
||||
/**
|
||||
* @return 自定义模式下的执行函数
|
||||
*/
|
||||
public SaFunction getFunction() {
|
||||
public SaRouteFunction getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param function 设置自定义模式下的执行函数
|
||||
*/
|
||||
public SaRouteInterceptor setFunction(SaFunction function) {
|
||||
public SaRouteInterceptor setFunction(SaRouteFunction function) {
|
||||
this.type = SaRouteInterceptor.CUSTOM;
|
||||
this.function = function;
|
||||
return this;
|
||||
@ -171,7 +171,7 @@ public class SaRouteInterceptor implements HandlerInterceptor {
|
||||
* 创建 (默认为自定义认证)
|
||||
* @param function 自定义模式下的执行函数
|
||||
*/
|
||||
public SaRouteInterceptor(SaFunction function) {
|
||||
public SaRouteInterceptor(SaRouteFunction function) {
|
||||
this(SaRouteInterceptor.CUSTOM, null, new String[0]);
|
||||
setFunction(function);
|
||||
}
|
||||
@ -207,7 +207,7 @@ public class SaRouteInterceptor implements HandlerInterceptor {
|
||||
* @param function 自定义模式下的执行函数
|
||||
* @return sa拦截器
|
||||
*/
|
||||
public static SaRouteInterceptor createCustomVal(SaFunction function) {
|
||||
public static SaRouteInterceptor createCustomVal(SaRouteFunction function) {
|
||||
return new SaRouteInterceptor(function);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user