Skip to content

历史可选方案:Token 存储与 Sa-Token ​

本文适用于需要维护旧 Sa-Token 集成的项目。当前 tio-boot-admin 默认使用框架 Token/JWT 鉴权,标准接入无需添加 Sa-Token 依赖、配置类或表。请先阅读 入门指南 和 配置职责说明。本文保留旧版实现供参考,类名、表名与依赖需按旧项目实际版本核对;涉及 SQL 仍由用户手动执行。

使用数据库存储 token ​

使用数据库存储 Sa-Token ​

tio-boot-admin 默认不再使用 Sa-Token 进行用户鉴权。可以舍弃本节 如果需要将 Sa-Token 的数据存储在数据库中,需要添加的表如下。


1. 数据表创建 ​

在数据库中创建一张用于存储 Sa-Token 数据的表,SQL 脚本如下: postgres

sql
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

sql
CREATE TABLE `tio_boot_admin_admin_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 数据:

java
package nexus.io.tio.boot.admin.dao;

import java.util.List;
import nexus.io.db.activerecord.Db;
import nexus.io.db.activerecord.Row;
import nexus.io.satoken.SaJdkSerializer;
import cn.dev33.satoken.dao.SaTokenDao;

public class SaTokenDbDao implements SaTokenDao {

    public static final String tableName = "tio_boot_admin_admin_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 的数据访问层:

java
import cn.dev33.satoken.SaManager;

public class TioAdminSaTokenConfiguration {

    public void config() {
        SaManager.setSaTokenDao(new SaTokenDbDao());
    }
}

调用 SaTokenConfig.config() 完成配置。

4. 存储的数据示例 ​

IDValueTimeoutOBOB_TimeoutRemark
authorization:login:token:87a998f30e204ef2879d35835f4f068412592000NullNullNull
authorization:login:last-active:87a998f30e204ef2879d35835f4f068417319768886972592000NullNullNull

总结 ​

通过上述步骤,我们成功实现了将 Sa-Token 的数据存储到数据库中。关键点如下:

  • 创建数据库表 tio_boot_admin_admin_token。
  • 实现 SaTokenDao 接口的 SaTokenDbDao 类。
  • 配置 Sa-Token 使用自定义的数据访问层。

这样一来,系统可以利用数据库的优势,支持持久化存储、更复杂的查询操作及分布式应用。

MIT Licensed