整合 Sa-Token
概述
Tio-Boot 已经内了内置对 Sa-Token 支持 ,提供了一种有效的方式来处理身份验证和授权。虽然 Tio-Boot 已有内置支持,但仍需手动添加 sa-token-core
依赖。此外,若希望将 token 存储在 Redis 中,还需要添加 java-db
、jedis
和 fst
依赖。
使用 Sa-Token 实现登录功能
存储 token 到浏览器
添加依赖
首先,需要在项目的 pom.xml
文件中添加以下依赖,以便引入必要的库:
<!-- Sa-Token 核心库 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>1.37.0</version>
</dependency>
配置 Sa-Token
接下来,需要设置 Sa-Token 的配置类。此类负责初始化 Sa-Token 相关的配置,如 token 的存储方式、有效期、cookie 配置等。
import com.litongjava.jfinal.aop.annotation.AConfiguration;
import com.litongjava.jfinal.aop.annotation.AInitialization;
import com.litongjava.tio.boot.satoken.SaTokenContextForTio;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaCookieConfig;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.util.SaTokenConsts;
@AConfiguration
public class SaTokenConfiguration {
@Initialization
public void config() {
// 初始化 Sa-Token 上下文
SaTokenContext saTokenContext = new SaTokenContextForTio();
// 设置 Cookie 配置,例如启用 HttpOnly 属性
SaCookieConfig saCookieConfig = new SaCookieConfig();
saCookieConfig.setHttpOnly(true);
// 初始化和配置 Sa-Token 主配置
SaTokenConfig saTokenConfig = new SaTokenConfig();
saTokenConfig.setTokenStyle(SaTokenConsts.TOKEN_STYLE_SIMPLE_UUID);
saTokenConfig.setActiveTimeout(50 * 60); // 设置活动超时时间为 50 分钟
saTokenConfig.setIsShare(false);
saTokenConfig.setTokenName("token"); // 设置 token 的名称
saTokenConfig.setIsWriteHeader(true); // 将 token 写入响应头
saTokenConfig.setIsReadHeader(true); // 从请求头中读取 token
saTokenConfig.setCookie(saCookieConfig);
// 应用配置到 Sa-Token 管理器
SaManager.setConfig(saTokenConfig);
SaManager.setSaTokenContext(saTokenContext);
}
}
添加拦截器
为了对请求进行验证,需要设置一个拦截器,该拦截器将根据配置的规则允许或阻止请求。
// 导入必要的类和注解
import com.litongjava.jfinal.aop.annotation.AConfiguration;
import com.litongjava.jfinal.aop.annotation.AInitialization;
import com.litongjava.tio.boot.http.interceptor.HttpInterceptorModel;
import com.litongjava.tio.boot.http.interceptor.HttpInteceptorConfigure;
import com.litongjava.tio.boot.satoken.SaTokenInterceptor;
import com.litongjava.tio.boot.server.TioBootServer;
@AConfiguration
public class InterceptorConfiguration {
@Initialization
public void config() {
// 创建 SaToken 拦截器实例
SaTokenInterceptor saTokenInterceptor = new SaTokenInterceptor();
HttpInterceptorModel model = new HttpInterceptorModel();
model.setInterceptor(saTokenInterceptor);
model.addblockeUrl("/**"); // 拦截所有路由
model.addAlloweUrls("/register/*", "/auth/*"); // 设置例外路由
HttpInteceptorConfigure serverInteceptorConfigure = new HttpInteceptorConfigure();
serverInteceptorConfigure.add(model);
// 将拦截器配置添加到 Tio 服务器
TioBootServer.me().setServerInteceptorConfigure(serverInteceptorConfigure);
}
}
实现登录和登出逻辑
接下来,可以在控制器中实现登录和登出的逻辑。这将使应用能够处理用户身份验证。
// 导入必要的类和注解
package com.litongjava.tio.web.hello;
import com.litongjava.tio.boot.http.TioControllerContext;
import com.litongjava.tio.http.common.HttpResponse;
import com.litongjava.annotation.RequestPath;
import com.litongjava.tio.http.server.util.Resps;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import lombok.extern.slf4j.Slf4j;
@RequestPath("/auth")
@Slf4j
public class AuthController {
public Object doLogin() {
StpUtil.login("litong");
HttpResponse response = TioControllerContext.getResponse();
log.info("response", response);
return response;
}
public HttpResponse logout() {
StpUtil.logout();
SaResult ok = SaResult.ok("ok");
HttpResponse response = TioControllerContext.getResponse();
return Resps.json(response, ok);
}
public boolean validateToken() {
try {
StpUtil.checkLogin();
return true;
} catch (Exception e) {
return false;
}
}
}
验证访问权限
最后,可以创建一个 IndexController
来验证用户的登录状态。如果用户没有登录,他们将无法访问此控制器的路由。
// 导入必要的类和注解
package com.litongjava.tio.web.hello;
import com.litongjava.annotation.RequestPath;
@RequestPath("/")
public class IndexController {
@RequestPath()
public String index() {
return "index";
}
}
测试应用
运行应用后,可以通过以下 URL 测试登录、登出和验证 token 的功能:
- 登录:
http://localhost:8080/auth/doLogin?username=zhang&password=123456
- 登出:
http://localhost:8080/auth/logout
- 验证 Token:
http://localhost:8080/auth/validateToken
- 访问首页:
http://localhost:8080/
登录
登录成功会回返回下面的信息 请求头
token:c5edff10712b4c49b64da5b910ecdb53
or
Set-Cookie:token=c5edff10712b4c49b64da5b910ecdb53; Max-Age=2592000; Expires=Tue, 9 Apr 2024 23:07:50 -1000; Path=/; HttpOnly
上面两种方式使用任意一种方式进行验证都可以
验证
可以添加使用 cookie token=c5edff10712b4c49b64da5b910ecdb53
GET /auth/validateToken HTTP/1.1
Cookie: token=c5edff10712b4c49b64da5b910ecdb53; PHPSESSID=e11a6f19b3504fec816a3d07862341ec
也支持请求头参数 token
生成 JWT token
添加依赖
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>1.37.0</version>
</dependency>
修改 SaTokenConfiguration 添加 jwt 相关配置
saTokenConfig.setJwtSecretKey("asdasdasifhueuiwyurfewbfjsdafjk");
saTokenConfig.setTokenPrefix("Bearer");
StpLogicJwtForSimple stpLogicJwtForSimple = new StpLogicJwtForSimple();
StpUtil.setStpLogic(stpLogicJwtForSimple);
其他不变,正常登录即可
将 Token 存入 Redis
为什么要将访问 token 存入 Redis
将访问令牌(Token)存储在 Redis 中主要是出于以下原因:
易于管理过期时间: 访问令牌通常有一个有效期限。Redis 提供了设置键值对过期时间的功能,这使得管理令牌过期变得简单和自动化,过期的令牌会被自动从数据库中删除,从而节省存储空间。
支持分布式系统: 在微服务架构或分布式系统中,应用组件可能部署在不同的服务器或容器上。使用 Redis 存储访问令牌可以确保所有组件都能实时访问到最新的令牌信息,便于系统的扩展和维护。
可伸缩性: 即便后端服务器重启,因为 token 存储到 redis 中,重启后依然可以识别前端传递过来的 token
添加依赖
<!-- JFinal 插件,用于与 Redis 交互 -->
<dependency>
<groupId>com.litongjava</groupId>
<artifactId>java-db</artifactId>
<version>1.0.6</version>
</dependency>
<!-- Jedis,Redis 的 Java 客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.3</version>
</dependency>
<!-- FST 序列化工具,用于对象和字节流间的转换 -->
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
<version>2.57</version> <!-- 注意:更高版本不支持 JDK 8 -->
</dependency>
为了将 token 存储在 Redis 中,需要配置 Redis 连接,并让 Sa-Token 使用 Redis 来存储 token。
配置 Redis 连接
首先,创建一个配置类来启动和配置 Redis。 app.properties
redis.host=127.0.0.1
redis.port=6789
redis.password=fdsafgh
redis.database=2
redis.timeout=15000
redis.cacheName=main
package com.litongjava.tio.boot.admin.config;
import com.litongjava.jfinal.aop.annotation.AConfiguration;
import com.litongjava.jfinal.aop.annotation.AInitialization;
import com.litongjava.jfinal.plugin.redis.Cache;
import com.litongjava.jfinal.plugin.redis.Redis;
import com.litongjava.jfinal.plugin.redis.RedisPlugin;
import com.litongjava.tio.boot.server.TioBootServer;
import com.litongjava.tio.utils.environment.EnvUtils;
@AConfiguration
public class RedisPluginConfig {
@Initialization
public RedisPlugin redisPlugin() {
String host = EnvUtils.getStr("redis.host");
Integer port = EnvUtils.getInt("redis.port");
String password = EnvUtils.getStr("redis.password");
int redisTimeout = EnvUtils.getInt("redis.timeout", 60);
int redisDatabase = EnvUtils.getInt("redis.database", 0);
String cacheName = EnvUtils.get("redis.cacheName");
// 创建并启动 Redis 插件
RedisPlugin mainRedis = new RedisPlugin(cacheName, host, port, redisTimeout, password, redisDatabase);
mainRedis.start();
// 测试连接
Cache cache = Redis.use(cacheName);
cache.getJedis().connect();
TioBootServer.me().addDestroyMethod(mainRedis::stop);
return mainRedis;
}
}
使用 Sa-Token 的 Redis 存储
然后,在 Sa-Token 的配置中指定使用 Redis 来存储 token。
import com.litongjava.jfinal.plugin.satoken.SaTokenDaoRedis;
// 在 Sa-Token 配置类中添加
String cacheName = EnvUtils.get("redis.cacheName");
SaManager.setSaTokenDao(new SaTokenDaoRedis(cacheName));
通过这种方式,Sa-Token 将使用 Redis 作为 token 的存储介质,提高了应用的可伸缩性和性能。
总结
整合 Sa-Token 到并使用 Redis 作为存储,为应用提供了一种强大且灵活的方式来处理用户认证和会话管理。通过上述步骤,您可以轻松地在 Tio-Boot 项目中实现基于 token 的身份验证系统,并利用 Redis 的高性能和持久化特性来管理这些 token。
记得在实际部署应用时,根据实际环境调整 Redis 的连接配置,确保应用的安全性和性能。同时,您可能还需要对登录逻辑进行进一步的扩展,以支持例如用户验证、密码加密等功能。
这样,您就完成了 Sa-Token 在 Tio-Boot 中的整合,并能够处理复杂的身份验证和授权场景,为您的应用添加了一层安全的保护。
增加 Api Key
// 增加一个Api用户设置token永不过期,让外部系统通过这个token调用本系统
SaLoginModel loginModel = new SaLoginModel();
loginModel.setTimeout(-1);
loginModel.setToken("123456");
StpUtil.createLoginSession("1", loginModel);