mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-09-19 01:58:05 +08:00
OAuth2模块与会话登录模块 数据互通
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* 快速构建 调用 `StpUtil.login()` 时的 [配置参数 Model ]
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaLoginConfig {
|
||||
|
||||
/**
|
||||
* @param device 此次登录的客户端设备标识
|
||||
* @return SaLoginModel配置对象
|
||||
*/
|
||||
public static SaLoginModel setDevice(String device) {
|
||||
return create().setDevice(device);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isLastingCookie 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public static SaLoginModel setIsLastingCookie(Boolean isLastingCookie) {
|
||||
return create().setIsLastingCookie(isLastingCookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeout 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public static SaLoginModel setTimeout(Long timeout) {
|
||||
return create().setTimeout(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param extraData 扩展信息(只在jwt模式下生效)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public static SaLoginModel setExtraData(Map<String, Object> extraData) {
|
||||
return create().setExtraData(extraData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token 预定Token(预定本次登录生成的Token值)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public static SaLoginModel setToken(String token) {
|
||||
return create().setToken(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入扩展数据(只在jwt模式下生效)
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return 对象自身
|
||||
*/
|
||||
public static SaLoginModel setExtra(String key, Object value) {
|
||||
return create().setExtra(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态方法获取一个 SaLoginModel 对象
|
||||
* @return SaLoginModel 对象
|
||||
*/
|
||||
public static SaLoginModel create() {
|
||||
return new SaLoginModel();
|
||||
}
|
||||
|
||||
}
|
@@ -35,16 +35,21 @@ public class SaLoginModel {
|
||||
*/
|
||||
public Map<String, Object> extraData;
|
||||
|
||||
/**
|
||||
* 预定Token(预定本次登录生成的Token值)
|
||||
*/
|
||||
public String token;
|
||||
|
||||
|
||||
/**
|
||||
* @return 参考 {@link #device}
|
||||
* @return 此次登录的客户端设备标识
|
||||
*/
|
||||
public String getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param device 参考 {@link #device}
|
||||
* @param device 此次登录的客户端设备标识
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel setDevice(String device) {
|
||||
@@ -53,14 +58,14 @@ public class SaLoginModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 参考 {@link #isLastingCookie}
|
||||
* @return 参考 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
|
||||
*/
|
||||
public Boolean getIsLastingCookie() {
|
||||
return isLastingCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isLastingCookie 参考 {@link #isLastingCookie}
|
||||
* @param isLastingCookie 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel setIsLastingCookie(Boolean isLastingCookie) {
|
||||
@@ -69,14 +74,14 @@ public class SaLoginModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 参考 {@link #timeout}
|
||||
* @return 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值)
|
||||
*/
|
||||
public Long getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeout 参考 {@link #timeout}
|
||||
* @param timeout 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel setTimeout(long timeout) {
|
||||
@@ -85,14 +90,14 @@ public class SaLoginModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 参考 {@link #extraData}
|
||||
* @return 扩展信息(只在jwt模式下生效)
|
||||
*/
|
||||
public Map<String, Object> getExtraData() {
|
||||
return extraData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param extraData 参考 {@link #extraData}
|
||||
* @param extraData 扩展信息(只在jwt模式下生效)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel setExtraData(Map<String, Object> extraData) {
|
||||
@@ -100,11 +105,39 @@ public class SaLoginModel {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 预定Token(预定本次登录生成的Token值)
|
||||
*/
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token 预定Token(预定本次登录生成的Token值)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel setToken(String token) {
|
||||
this.token = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* toString
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaLoginModel [device=" + device + ", isLastingCookie=" + isLastingCookie + ", timeout=" + timeout
|
||||
+ ", extraData=" + extraData + ", token=" + token + "]";
|
||||
}
|
||||
|
||||
// ------ 附加方法
|
||||
|
||||
|
||||
/**
|
||||
* 写入扩展数据(只在jwt模式下生效)
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel setExtra(String key, Object value) {
|
||||
if(this.extraData == null) {
|
||||
@@ -183,14 +216,6 @@ public class SaLoginModel {
|
||||
return new SaLoginModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* toString
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaLoginModel [device=" + device + ", isLastingCookie=" + isLastingCookie + ", timeout=" + timeout + "]";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更换为 getDeviceOrDefault()
|
||||
|
@@ -274,6 +274,29 @@ public class StpLogic {
|
||||
* @param loginModel 此次登录的参数Model
|
||||
*/
|
||||
public void login(Object id, SaLoginModel loginModel) {
|
||||
// 1、创建会话
|
||||
String token = createLoginSession(id, loginModel);
|
||||
|
||||
// 2、在当前客户端注入Token
|
||||
setTokenValue(token, loginModel.getCookieTimeout());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定账号id的登录会话
|
||||
* @param id 登录id,建议的类型:(long | int | String)
|
||||
* @return 返回会话令牌
|
||||
*/
|
||||
public String createLoginSession(Object id) {
|
||||
return createLoginSession(id, new SaLoginModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定账号id的登录会话
|
||||
* @param id 登录id,建议的类型:(long | int | String)
|
||||
* @param loginModel 此次登录的参数Model
|
||||
* @return 返回会话令牌
|
||||
*/
|
||||
public String createLoginSession(Object id, SaLoginModel loginModel) {
|
||||
|
||||
SaTokenException.throwByNull(id, "账号id不能为空");
|
||||
|
||||
@@ -300,7 +323,11 @@ public class StpLogic {
|
||||
}
|
||||
// 如果至此,仍未成功创建tokenValue, 则开始生成一个
|
||||
if(tokenValue == null) {
|
||||
if(SaFoxUtil.isEmpty(loginModel.getToken())) {
|
||||
tokenValue = createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getTimeout(), loginModel.getExtraData());
|
||||
} else {
|
||||
tokenValue = loginModel.getToken();
|
||||
}
|
||||
}
|
||||
|
||||
// ------ 3. 获取 User-Session , 续期
|
||||
@@ -314,14 +341,14 @@ public class StpLogic {
|
||||
// token -> id 映射关系
|
||||
saveTokenToIdMapping(tokenValue, id, loginModel.getTimeout());
|
||||
|
||||
// 在当前会话写入tokenValue
|
||||
setTokenValue(tokenValue, loginModel.getCookieTimeout());
|
||||
|
||||
// 写入 [token-last-activity]
|
||||
setLastActivityToNow(tokenValue);
|
||||
|
||||
// $$ 通知监听器,账号xxx 登录成功
|
||||
SaManager.getSaTokenListener().doLogin(loginType, id, loginModel);
|
||||
|
||||
// 返回Token
|
||||
return tokenValue;
|
||||
}
|
||||
|
||||
// --- 注销
|
||||
|
@@ -132,6 +132,25 @@ public class StpUtil {
|
||||
stpLogic.login(id, loginModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定账号id的登录会话
|
||||
* @param id 登录id,建议的类型:(long | int | String)
|
||||
* @return 返回会话令牌
|
||||
*/
|
||||
public static String createLoginSession(Object id) {
|
||||
return stpLogic.createLoginSession(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定账号id的登录会话
|
||||
* @param id 登录id,建议的类型:(long | int | String)
|
||||
* @param loginModel 此次登录的参数Model
|
||||
* @return 返回会话令牌
|
||||
*/
|
||||
public static String createLoginSession(Object id, SaLoginModel loginModel) {
|
||||
return stpLogic.createLoginSession(id, loginModel);
|
||||
}
|
||||
|
||||
// --- 注销
|
||||
|
||||
/**
|
||||
|
@@ -136,6 +136,25 @@ public class StpUserUtil {
|
||||
stpLogic.login(id, loginModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定账号id的登录会话
|
||||
* @param id 登录id,建议的类型:(long | int | String)
|
||||
* @return 返回会话令牌
|
||||
*/
|
||||
public static String createLoginSession(Object id) {
|
||||
return stpLogic.createLoginSession(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定账号id的登录会话
|
||||
* @param id 登录id,建议的类型:(long | int | String)
|
||||
* @param loginModel 此次登录的参数Model
|
||||
* @return 返回会话令牌
|
||||
*/
|
||||
public static String createLoginSession(Object id, SaLoginModel loginModel) {
|
||||
return stpLogic.createLoginSession(id, loginModel);
|
||||
}
|
||||
|
||||
// --- 注销
|
||||
|
||||
/**
|
||||
|
@@ -235,7 +235,6 @@ public class TestController {
|
||||
return AjaxJson.getSuccessData("登录成功");
|
||||
}
|
||||
|
||||
|
||||
// 测试 浏览器访问: http://localhost:8081/test/test
|
||||
@RequestMapping("test")
|
||||
public AjaxJson test() {
|
||||
|
@@ -50,6 +50,7 @@
|
||||
- [OAuth2-Server搭建](/oauth2/oauth2-server)
|
||||
- [OAuth2-Server端-API列表](/oauth2/oauth2-api)
|
||||
- [OAuth2-二次开发说明](/oauth2/oauth2-dev)
|
||||
- [OAuth2-与登录会话实现数据互通](/oauth2/oauth2-interworking)
|
||||
|
||||
- **微服务**
|
||||
- [分布式Session会话](/micro/dcs-session)
|
||||
|
65
sa-token-doc/doc/oauth2/oauth2-interworking.md
Normal file
65
sa-token-doc/doc/oauth2/oauth2-interworking.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Sa-Token-OAuth2 与登录会话实现数据互通
|
||||
|
||||
---
|
||||
|
||||
### 前提
|
||||
|
||||
前提,我们:
|
||||
- 把 OAuth2 模块生成的令牌称作资源令牌(access_token),
|
||||
- 把 StpUtil 登录会话生成的令牌称作会话令牌(satoken)。
|
||||
|
||||
正常情况下,资源令牌 与 会话令牌 的数据是不互通的,具体表现就是:当我们拿着 access_token 去访问 satoken 令牌的接口,会被抛出异常:`无效Token:xxxxx`
|
||||
|
||||
那么,有什么办法可以做到这两个模块的数据互通呢?
|
||||
|
||||
|
||||
|
||||
### OAuth2-Server 端数据互通
|
||||
|
||||
很简单,你只需要在 `SaOAuth2TemplateImpl` 实现类中继续重写 Access-Token 的生成策略:
|
||||
|
||||
``` java
|
||||
@Component
|
||||
public class SaOAuth2TemplateImpl extends SaOAuth2Template {
|
||||
|
||||
// ... 其它代码
|
||||
|
||||
// 重写 Access-Token 生成策略:复用登录会话的Token
|
||||
@Override
|
||||
public String randomAccessToken(String clientId, Object loginId, String scope) {
|
||||
String tokenValue = StpUtil.createLoginSession(loginId);
|
||||
return tokenValue;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
重启项目,然后在 OAuth2 模块授权登录,现在生成的 `access_token` ,可以用来访问 `satoken` 的会话接口了。
|
||||
|
||||
|
||||
### OAuth2-Client 数据互通
|
||||
除了Server端,Client端也可以打通 `access_token` 与 `satoken` 会话。做法是在 Client 端拿到 `access_token` 后进行登录时,使用 SaLoginModel 预定登录生成的 Token 值
|
||||
|
||||
``` java
|
||||
// 1. 获取到access_token
|
||||
String access_token = ...
|
||||
|
||||
// 2. 登录时预定生成的token
|
||||
StpUtil.login(uid, SaLoginConfig.setToken(access_token));
|
||||
|
||||
// 3. 其它代码...
|
||||
```
|
||||
|
||||
|
||||
### 注意点
|
||||
数据互通,让前端与后端的交互更加方便,一个 token 即可访问所有接口,但也一定程度上失去了OAuth2的 “不同 Client 不同权限” 的设计意义,
|
||||
同时也默认每个 Client 都拥有了账号的会话权限(access_token 与 satoken 为同一个)。
|
||||
|
||||
应该根据自己的架构合理分析是否应该整合数据互通。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -72,6 +72,7 @@ StpUtil.login(10001, new SaLoginModel()
|
||||
.setDevice("PC") // 此次登录的客户端设备标识, 用于[同端互斥登录]时指定此次登录的设备名称
|
||||
.setIsLastingCookie(true) // 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
|
||||
.setTimeout(60 * 60 * 24 * 7) // 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值)
|
||||
.setToken("xxxx-xxxx-xxxx-xxxx") // 预定此次登录的生成的Token
|
||||
);
|
||||
```
|
||||
|
||||
|
Reference in New Issue
Block a user