token 存储
使用数据库存储 Sa-Token
tio-boot-admin
默认使用 Sa-Token 进行用户鉴权。默认将 Sa-Token 的数据存储在数据库中,需要添加的表如下。
1. 数据表创建
在数据库中创建一张用于存储 Sa-Token 数据的表,SQL 脚本如下: postgres
CREATE TABLE "tio_boot_admin_sa_token" (
"id" VARCHAR PRIMARY KEY, -- Token ID
"value" VARCHAR, -- Token 值
"timeout" INT8, -- Token 过期时间
"ob" BYTEA, -- 对象存储(序列化后的字节数组)
"ob_timeout" INT8, -- 对象过期时间
remark VARCHAR(256), -- 备注
creator VARCHAR(64) DEFAULT '', -- 创建人
create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
updater VARCHAR(64) DEFAULT '', -- 更新人
update_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
deleted SMALLINT DEFAULT 0, -- 删除标志
tenant_id BIGINT NOT NULL DEFAULT 0 -- 租户 ID
);
mysql
CREATE TABLE `tio_boot_admin_sa_token` (
`id` VARCHAR(255) PRIMARY KEY COMMENT 'Token ID',
`value` VARCHAR(255) COMMENT 'Token 值',
`timeout` BIGINT COMMENT 'Token 过期时间',
`ob` BLOB COMMENT '对象存储(序列化后的字节数组)',
`ob_timeout` BIGINT COMMENT '对象过期时间',
`remark` VARCHAR(256) COMMENT '备注',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建人',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新人',
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` SMALLINT DEFAULT 0 COMMENT '删除标志',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID'
);
2. 自定义 Sa-Token 数据访问层
tio-boot-admin 已经内置了 SaTokenDao
实现 SaTokenDao
接口
实现一个 SaTokenDbDao
类,用于操作数据库中的 Sa-Token 数据:
package com.litongjava.tio.boot.admin.dao;
import java.util.List;
import com.litongjava.db.activerecord.Db;
import com.litongjava.db.activerecord.Row;
import com.litongjava.satoken.SaJdkSerializer;
import cn.dev33.satoken.dao.SaTokenDao;
public class SaTokenDbDao implements SaTokenDao {
public static final String tableName = "tio_boot_admin_sa_token";
String get_value_sql = String.format("select value from %s where id=?", tableName);
String get_timeout_sql = String.format("select timeout from %s where id=?", tableName);
String get_object_sql = String.format("select ob from %s where id=?", tableName);
String get_object_timeout_sql = String.format("select ob_timeout from %s where id=?", tableName);
@Override
public String get(String key) {
return Db.queryStr(get_value_sql, key);
}
@Override
public void set(String key, String value, long timeout) {
Row row = Row.by("id", key).set("value", value).set("timeout", timeout);
if (Db.exists(tableName, "id", key)) {
Db.update(tableName, row);
} else {
Db.save(tableName, row);
}
}
@Override
public void update(String key, String value) {
Row row = Row.by("id", key).set("value", value);
Db.update(tableName, row);
}
@Override
public void delete(String key) {
Db.deleteById(tableName, "id", key);
}
@Override
public long getTimeout(String key) {
return Db.queryLong(get_timeout_sql, key);
}
@Override
public void updateTimeout(String key, long timeout) {
Row row = Row.by("id", key).set("timeout", timeout);
Db.update(tableName, "id", row);
}
@Override
public Object getObject(String key) {
byte[] queryFirst = Db.quereyBytes(get_object_sql, key);
return SaJdkSerializer.me.valueFromBytes(queryFirst);
}
@Override
public void setObject(String key, Object object, long timeout) {
byte[] valueToBytes = SaJdkSerializer.me.valueToBytes(object);
Row row = Row.by("id", key).set("ob", valueToBytes).set("ob_timeout", timeout);
if (Db.exists(tableName, "id", key)) {
Db.update(tableName, row);
} else {
Db.save(tableName, row);
}
}
@Override
public void updateObject(String key, Object object) {
byte[] valueToBytes = SaJdkSerializer.me.valueToBytes(object);
Row row = Row.by("id", key).set("ob", valueToBytes);
Db.update(tableName, "id", row);
}
@Override
public void deleteObject(String key) {
Db.deleteById(tableName, "id", key);
}
@Override
public long getObjectTimeout(String key) {
return Db.queryLong(get_object_timeout_sql, key);
}
@Override
public void updateObjectTimeout(String key, long timeout) {
Row row = Row.by("id", key).set("ob_timeout", timeout);
Db.update(tableName, "id", row);
}
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
return null; // 可根据需求实现搜索功能
}
}
3. 配置 Sa-Token 使用自定义数据访问层
在项目中将自定义的 SaTokenDbDao
配置为 Sa-Token 的数据访问层:
import cn.dev33.satoken.SaManager;
public class TioAdminSaTokenConfiguration {
public void config() {
SaManager.setSaTokenDao(new SaTokenDbDao());
}
}
调用 SaTokenConfig.config()
完成配置。
4. 存储的数据示例
ID | Value | Timeout | OB | OB_Timeout | Remark |
---|---|---|---|---|---|
authorization:login:token:87a998f30e204ef2879d35835f4f0684 | 1 | 2592000 | Null | Null | Null |
authorization:login:last-active:87a998f30e204ef2879d35835f4f0684 | 1731976888697 | 2592000 | Null | Null | Null |
总结
通过上述步骤,我们成功实现了将 Sa-Token 的数据存储到数据库中。关键点如下:
- 创建数据库表
tio_boot_admin_sa_token
。 - 实现
SaTokenDao
接口的SaTokenDbDao
类。 - 配置 Sa-Token 使用自定义的数据访问层。
这样一来,系统可以利用数据库的优势,支持持久化存储、更复杂的查询操作及分布式应用。