Sa-Token/sa-token-doc/arch/data-structure.md
2025-12-24 01:14:50 +08:00

12 KiB
Raw Permalink Blame History

数据结构

1、登录会话

1.1、token -> loginId 映射

// ttl = 此 token 的 timeout 有效期
{tokenName}:{loginType}:token:{tokenValue}  -->  {loginId}
详细

示例:

satoken:login:token:47ab0105-2be1-400c-b517-82f81a0cfcf8  -->  10001

异常 value 格式

-1       未能从请求中读取到有效 token
-2       已读取到 token但是 token 无效
-3       已读取到 token但是 token 已经过期 ()
-4       已读取到 token但是 token 已被顶下线
-5       已读取到 token但是 token 已被踢下线
-6       已读取到 token但是 token 已被冻结
-7       未按照指定前缀提交 token

1.2、active-timeout

// ttl = 对应 token 的 timeout 有效期值
{tokenName}:{loginType}:last-active:{tokenValue}  -->  {13位时间戳}
详细

示例:

satoken:login:last-active:06d1f12b-614e-4c00-8d8e-c07fef5f4aa9   -->   1722334954193

value 格式分两种:

1722334954193          // 单值时:此 token 最后访问日期
1722334954193, 1200    // 双值时:此 token 最后访问日期,此 token 指定的动态 active-timeout 值 

注意:判断一个 token 是否 active-timeout 过期,与 ttl 无关,而是利 value 值计算:

当前时间 - token 最后访问时间 > active-timeout   true=token 已冻结false=token 未冻结 

1.3、SaSession

{tokenName}:{loginType}:session:{loginId}  -->  {SaSession 对象}        // Account-Session
{tokenName}:{loginType}:token-session:{loginId}  -->  {SaSession 对象}  // Token-Session
{tokenName}:custom:session:{sessionId}  -->  {SaSession 对象}           // Custom-Session
详细

key 示例

// Account-Session
satoken:login:session:1000001

// Token-Session
satoken:login:session:47ab0105-2be1-400c-b517-82f81a0cfcf8

// Custom-Session
satoken:custom:session:role-1001

value 格式

{
  "@class": "cn.dev33.satoken.dao.SaSessionForJacksonCustomized",    // java calss 信息
  "id": "satoken:login:session:10001",    // sessionId
  "type": "Account-Session",    // session类型Account-Session / Token-Session / Custom-Session
  "loginType": "login",     // 账号类型 
  "loginId": [    // 对应登录id 值Account-Session才会有值
    "java.lang.Long",
    10001
  ],    
  "token": null,    // 对应 token 值 Token-Session才会有值
  "createTime": 1722334954145,    // 此 session 创建时间13位时间戳 
  "dataMap": {    // 此 session 挂载数据 
    "@class": "java.util.concurrent.ConcurrentHashMap", 
    "name": "张三"    // 此 session 挂载数据 详情
	// 更多值 ...
  },
  "terminalList": [		// 已登录终端信息列表Account-Session才会有值
    "java.util.Vector",
    [
      {
        "@class": "cn.dev33.satoken.session.SaTerminalInfo",
        "index": 1,
        "tokenValue": "2551663f-bb98-47d7-9af3-e2e6a28dadce",   // 客户端 token 值
        "deviceType": "DEF",  // 登录设备类型 
        "deviceId": "xxxxxxxxx",  // 登录设备id 
        "extraData": {
			// 扩展信息列表 (手动自定义值)
			"@class": "java.util.LinkedHashMap",
			"deviceSimpleTitle": "XiaoMi 15 Ultra",
			"loginAddress": "浙江省杭州市西湖区",
			"loginIp": "127.0.0.1",
			"loginTime": "2025-03-08 15:00:02"
        },
        "createTime": 1741406340845 // 登录时间 
      }
    ]
  ]
}

1.4、二级认证

{tokenName}:{loginType}:safe:{service}:{tokenValue}  -->  SAFE_AUTH_SAVE_VALUE

value 为常亮值:SAFE_AUTH_SAVE_VALUE

1.5、账号服务封禁

{tokenName}:{loginType}:disable:{service}:{loginId}  -->  {level}

value 为封禁等级int类型

1.6、其它

SaApplication 全局变量

{tokenName}:var:{变量名}

本次请求新创建 token在 SaStorage 存储 key

JUST_CREATED_  -->  {token}

本次请求新创建 token在 SaStorage 存储 key (无前缀方式)

JUST_CREATED_NOT_PREFIX_  -->  {token}

临时身份切换使用的key

SWITCH_TO_SAVE_KEY_{loginType}  -->  {loginId}

2、SSO 单点登录

2.1、ticket -> loginId 映射

// ttl = 此 ticket 有效期,下同理 
{tokenName}:ticket:{ticket}  -->  {loginId}

2.2、ticket -> client 映射

{tokenName}:ticket-client:{ticket}  -->  {client}

2.3、loginId -> ticket 映射client + loginId 反查 ticket

{tokenName}:ticket-index:{client}:{loginId}  -->  {ticket}

3、OAuth2 统一认证

3.1、Code 授权码

{tokenName}:oauth2:code:{code}  -->  {CodeModel 对象}
详细

value 示例:

{
	"@class": "cn.dev33.satoken.oauth2.model.CodeModel",    // java class 信息
	"code": "AbRVp2HrgyklE0BXYWszskGJWAGY7xhGu6Zaco4zJECzGYagCCFWj0jOlHza",    // code值
	"scope": "",    // 所申请权限列表,多个用逗号隔开
	"loginId": "10001",    // 对应的loginId
	"redirectUri": "",    // 重定向地址
}

clientId + loginId 反查 code

{tokenName}:oauth2:code-index:{clientId}:{loginId}  -->  {code }

3.2、Access-Token 资源令牌

{tokenName}:oauth2:access-token:{accessToken}  -->  {AccessTokenModel 对象}
详细

value 示例:

{
  "@class": "cn.dev33.satoken.oauth2.data.model.AccessTokenModel",    // java class 信息
  "accessToken": "Pu3t55dJIgvkmVoHz50FqaVQOJ6Flggjr2eHTiS74Ooai8e3nNyYPq78K80P",    // 资源令牌值
  "refreshToken": "baGyl6PHK304tPojnpxd1SpW12oJcOGv7gFaDAAkjLWbJG1J1WLUIGobsw7m",    // 刷新令牌值
  "expiresTime": 1738280553695,    // 资源令牌到期时间
  "refreshExpiresTime": 1740865353760,    // 刷新令牌到期时间
  "clientId": "1001",    // 对应的应用id
  "loginId": "10001",    // 对应的loginId
  "scopes": [   // 所具有的权限列表 
    "java.util.ArrayList",
    [
      "userinfo",
      "userid",
      "openid",
      "unionid",
      "oidc"
    ]
  ],
  "tokenType": "bearer",   // tokenType 
  "grantType": "authorization_code",   // 授权方式 
  "extraData": {   // 扩展数据  
    "@class": "java.util.LinkedHashMap",
    "userid": "10001",
    "openid": "ded91dc189a437dd1bac2274be167d50",
    "unionid": "11d48faa74c4e5f19355ccc53c1c5c7a",
    "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vc2Etb2F1dGgtc2VydmVyLmNvbTo4MDAwIiwic3ViIjoiMTAwMDEiLCJhdWQiOiIxMDAxIiwiZXhwIjoxNzM4MjczOTUzLCJpYXQiOjE3MzgyNzMzNTMsImF1dGhfdGltZSI6MTczODI3MzM0Miwibm9uY2UiOiJZQTlPQjJzYkpGanZkUlFjN0E3V1pnTUFhTDFVRjE5OSIsImF6cCI6IjEwMDEifQ.pvoj6CR7tdhOblvYJoGUfvam9egSiL5Uw3tflLLMb5g"
  },
  "createTime": 1738273353694,   // 创建时间   
  "expiresIn": 7199    // 资源令牌剩余有效时间,单位秒
  "refreshExpiresIn": 2592000,    // 刷新令牌剩余有效时间,单位秒
}

clientId + loginId 反查 Access-Token

{tokenName}:oauth2:access-token-index:{clientId}:{loginId}  -->  {access_token }

3.3、Refresh-Token 资源令牌

{tokenName}:oauth2:refresh-token:{refreshToken}  -->  {RefreshTokenModel 对象}
详细

value 示例:

{
  "@class": "cn.dev33.satoken.oauth2.data.model.RefreshTokenModel",    // java class 信息
  "refreshToken": "baGyl6PHK304tPojnpxd1SpW12oJcOGv7gFaDAAkjLWbJG1J1WLUIGobsw7m",    // 刷新令牌值
  "expiresTime": 1740865353760,   // 刷新令牌到期时间
  "clientId": "1001",    // 对应的应用id
  "loginId": "10001",    // 对应的loginId
  "scopes": [    // 所具有的权限列表 
    "java.util.ArrayList",
    [
      "userinfo",
      "userid",
      "openid",
      "unionid",
      "oidc"
    ]
  ],
  "extraData": {   // 扩展数据  
    "@class": "java.util.LinkedHashMap",
    "userid": "10001",
    "openid": "ded91dc189a437dd1bac2274be167d50",
    "unionid": "11d48faa74c4e5f19355ccc53c1c5c7a",
    "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vc2Etb2F1dGgtc2VydmVyLmNvbTo4MDAwIiwic3ViIjoiMTAwMDEiLCJhdWQiOiIxMDAxIiwiZXhwIjoxNzM4MjczOTUzLCJpYXQiOjE3MzgyNzMzNTMsImF1dGhfdGltZSI6MTczODI3MzM0Miwibm9uY2UiOiJZQTlPQjJzYkpGanZkUlFjN0E3V1pnTUFhTDFVRjE5OSIsImF6cCI6IjEwMDEifQ.pvoj6CR7tdhOblvYJoGUfvam9egSiL5Uw3tflLLMb5g"
  },
  "createTime": 1738273353760,   // 创建时间   
  "expiresIn": 2591999    // 刷新令牌剩余有效时间,单位秒
}

clientId + loginId 反查 Refresh-Token

{tokenName}:oauth2:refresh-token-index:{clientId}:{loginId}  -->  {refresh_token }

3.4、Client-Token 应用令牌

{tokenName}:oauth2:client-token:{clientToken}  -->  {ClientTokenModel 对象}
详细

value 示例:

{
  "@class": "cn.dev33.satoken.oauth2.data.model.ClientTokenModel",    // java class 信息
  "clientToken": "lIpS3fKEACKMFauEWVpR7Zmzh7SoFetPVuB9aDzISnqzHKu8R3OwpWFy5nLv",    // 应用令牌值 
  "expiresTime": 1738280930646,    // 应用令牌到期时间
  "clientId": "1001",    // 对应的应用id
  "scopes": [    // 所具有的权限列表 
    "java.util.ArrayList",
    [
      "userinfo",
      "userid",
      "openid",
      "unionid",
      "oidc"
    ]
  ],
  "tokenType": "bearer",   // tokenType   
  "grantType": "client_credentials",   // 授权类型    
  "extraData": {   // 扩展数据
    "@class": "java.util.LinkedHashMap"
  },
  "createTime": 1738273730646,   // 创建时间   
  "expiresIn": 7199    // 应用令牌剩余有效时间,单位秒
}

clientId 反查 Client-Token

{tokenName}:oauth2:client-token-index:{clientId}  -->  {client_token }

Lower-Client-Token 次级应用令牌索引

{tokenName}:oauth2:lower-client-token-index:{clientId}  -->  {client_token }

3.5、用户授权记录

{tokenName}:oauth2:grant-scope:{clientId}:{loginId}  -->  {scope列表}

值为 scope 列表,多个用逗号隔开,例如:userinfo,openid,userid

4、插件

4.1、临时 token 会话

temp-token -> value

// namespace 默认值为 "temp-token"
{tokenName}:{namespace}:{temp-token}  -->  {value}

value 反查 temp-token

{tokenName}:raw-session:{namespace}:{value}  -->  {Raw#SaSession 对象}
  • 在 SaSession 以 __HD_TEMP_TOKEN_MAP 为 key 存储 temp-token 索引列表。值类型为 Map。
  • 其中Map 的 key = temp-token 值Map 的 value = 此 temp-token 到期时间戳。

4.2、 Same-Token

Same-Token

{tokenName}:var:same-token  -->  {same-token }

Past-Same-Token

{tokenName}:var:past-same-token  -->  {same-token }

4.3、Sign 签名

随机字符串

// nonce 值 默认为 32位随机字符
{tokenName}:sign:nonce:{nonce}  -->  {nonce }

4.4、API Key

// namespace 默认值为 "apikey" (全小写), ttl = 此 API Key 剩余有效期 
{tokenName}:{namespace}:{apikey}  -->  {ApiKeyModel 对象}
详细

key 示例:

satoken:apikey:AK-XCoJLP2E7Q9GXyPiiZWMM8Sqi6Fm0JoFC41R

value 示例:

{
	"@class": "cn.dev33.satoken.apikey.model.ApiKeyModel",   // java class 信息
	"title": "test",   // API Key 名称 
	"intro": null,   // 用途介绍
	"apiKey": "AK-XCoJLP2E7Q9GXyPiiZWMM8Sqi6Fm0JoFC41R",   // API Key 值
	"loginId": "10001",   // 所属用户 id
	"createTime": 1766509019137,   // 创建时间戳
	"expiresTime": 1769101019136,   // 到期时间戳
	"isValid": true,   // 是否有效
	"scopes": [   // 含有权限
		"java.util.ArrayList",
		[
		  "userinfo",
		  "user-update"
		]
	],
	"extraData": null   // 扩展数据Map<String, Object> 类型 
}

value 反查 API Key

{tokenName}:raw-session:{namespace}:{value}  -->  {Raw#SaSession 对象}
  • 在 SaSession 以 __HD_API_KEY_LIST 为 key 存储 API Key 索引列表。值类型为 List (API Key 列表)。