1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
// Author: 金书记
//
//! 配置模块
use std::time::Duration;
use std::sync::Arc;
use serde::{Deserialize, Serialize};
use sa_token_adapter::storage::SaStorage;
use crate::event::SaTokenListener;
/// sa-token 配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SaTokenConfig {
/// Token 名称(例如在 header 或 cookie 中的键名)
pub token_name: String,
/// Token 有效期(秒),-1 表示永久有效
pub timeout: i64,
/// Token 最低活跃频率(秒),-1 表示不限制
///
/// 配合 auto_renew 使用时,表示自动续签的时长
pub active_timeout: i64,
/// 是否开启自动续签(默认 false)
///
/// 如果设置为 true,在以下场景会自动续签 token:
/// - 调用 get_token_info() 时
/// - 中间件验证 token 时
/// - 调用无参数的 StpUtil 方法时
///
/// 续签时长由 active_timeout 决定:
/// - 如果 active_timeout > 0,则续签 active_timeout 秒
/// - 如果 active_timeout <= 0,则续签 timeout 秒
pub auto_renew: bool,
/// 是否允许同一账号并发登录
pub is_concurrent: bool,
/// 在多人登录同一账号时,是否共享一个 token
pub is_share: bool,
/// Token 风格(uuid、simple-uuid、random-32、random-64、random-128)
pub token_style: TokenStyle,
/// 是否输出操作日志
pub is_log: bool,
/// 是否从 cookie 中读取 token
pub is_read_cookie: bool,
/// 是否从 header 中读取 token
pub is_read_header: bool,
/// 是否从请求体中读取 token
pub is_read_body: bool,
/// token 前缀(例如 "Bearer ")
pub token_prefix: Option<String>,
/// JWT 密钥(如果使用 JWT)
pub jwt_secret_key: Option<String>,
/// JWT 算法(默认 HS256)
pub jwt_algorithm: Option<String>,
/// JWT 签发者
pub jwt_issuer: Option<String>,
/// JWT 受众
pub jwt_audience: Option<String>,
/// 是否启用防重放攻击(nonce 机制)
pub enable_nonce: bool,
/// Nonce 有效期(秒),-1 表示使用 token timeout
pub nonce_timeout: i64,
/// 是否启用 Refresh Token
pub enable_refresh_token: bool,
/// Refresh Token 有效期(秒),默认 7 天
pub refresh_token_timeout: i64,
}
impl Default for SaTokenConfig {
fn default() -> Self {
Self {
token_name: "sa-token".to_string(),
timeout: 2592000, // 30天
active_timeout: -1,
auto_renew: false, // 默认不开启自动续签
is_concurrent: true,
is_share: true,
token_style: TokenStyle::Uuid,
is_log: false,
is_read_cookie: true,
is_read_header: true,
is_read_body: false,
token_prefix: None,
jwt_secret_key: None,
jwt_algorithm: Some("HS256".to_string()),
jwt_issuer: None,
jwt_audience: None,
enable_nonce: false,
nonce_timeout: -1,
enable_refresh_token: false,
refresh_token_timeout: 604800, // 7 天
}
}
}
impl SaTokenConfig {
pub fn builder() -> SaTokenConfigBuilder {
SaTokenConfigBuilder::default()
}
pub fn timeout_duration(&self) -> Option<Duration> {
if self.timeout < 0 {
None
} else {
Some(Duration::from_secs(self.timeout as u64))
}
}
}
/// Token 风格 | Token Style
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum TokenStyle {
/// UUID 风格 | UUID style
Uuid,
/// 简化的 UUID(去掉横杠)| Simple UUID (without hyphens)
SimpleUuid,
/// 32位随机字符串 | 32-character random string
Random32,
/// 64位随机字符串 | 64-character random string
Random64,
/// 128位随机字符串 | 128-character random string
Random128,
/// JWT 风格(JSON Web Token)| JWT style (JSON Web Token)
Jwt,
/// Hash 风格(SHA256哈希)| Hash style (SHA256 hash)
Hash,
/// 时间戳风格(毫秒级时间戳+随机数)| Timestamp style (millisecond timestamp + random)
Timestamp,
/// Tik 风格(短小精悍的8位字符)| Tik style (short 8-character token)
Tik,
}
/// 配置构建器
#[derive(Default)]
pub struct SaTokenConfigBuilder {
config: SaTokenConfig,
storage: Option<Arc<dyn SaStorage>>,
listeners: Vec<Arc<dyn SaTokenListener>>,
}
impl SaTokenConfigBuilder {
pub fn token_name(mut self, name: impl Into<String>) -> Self {
self.config.token_name = name.into();
self
}
pub fn timeout(mut self, timeout: i64) -> Self {
self.config.timeout = timeout;
self
}
pub fn active_timeout(mut self, timeout: i64) -> Self {
self.config.active_timeout = timeout;
self
}
/// 设置是否开启自动续签
pub fn auto_renew(mut self, enabled: bool) -> Self {
self.config.auto_renew = enabled;
self
}
pub fn is_concurrent(mut self, concurrent: bool) -> Self {
self.config.is_concurrent = concurrent;
self
}
pub fn is_share(mut self, share: bool) -> Self {
self.config.is_share = share;
self
}
pub fn token_style(mut self, style: TokenStyle) -> Self {
self.config.token_style = style;
self
}
pub fn token_prefix(mut self, prefix: impl Into<String>) -> Self {
self.config.token_prefix = Some(prefix.into());
self
}
pub fn jwt_secret_key(mut self, key: impl Into<String>) -> Self {
self.config.jwt_secret_key = Some(key.into());
self
}
/// 设置 JWT 算法
pub fn jwt_algorithm(mut self, algorithm: impl Into<String>) -> Self {
self.config.jwt_algorithm = Some(algorithm.into());
self
}
/// 设置 JWT 签发者
pub fn jwt_issuer(mut self, issuer: impl Into<String>) -> Self {
self.config.jwt_issuer = Some(issuer.into());
self
}
/// 设置 JWT 受众
pub fn jwt_audience(mut self, audience: impl Into<String>) -> Self {
self.config.jwt_audience = Some(audience.into());
self
}
/// 启用防重放攻击(nonce 机制)
pub fn enable_nonce(mut self, enable: bool) -> Self {
self.config.enable_nonce = enable;
self
}
/// 设置 Nonce 有效期(秒)
pub fn nonce_timeout(mut self, timeout: i64) -> Self {
self.config.nonce_timeout = timeout;
self
}
/// 启用 Refresh Token
pub fn enable_refresh_token(mut self, enable: bool) -> Self {
self.config.enable_refresh_token = enable;
self
}
/// 设置 Refresh Token 有效期(秒)
pub fn refresh_token_timeout(mut self, timeout: i64) -> Self {
self.config.refresh_token_timeout = timeout;
self
}
/// 设置存储方式
pub fn storage(mut self, storage: Arc<dyn SaStorage>) -> Self {
self.storage = Some(storage);
self
}
/// 注册事件监听器
///
/// 可以多次调用以注册多个监听器
///
/// # 示例
/// ```rust,ignore
/// use std::sync::Arc;
/// use sa_token_core::{SaTokenConfig, SaTokenListener};
///
/// struct MyListener;
/// impl SaTokenListener for MyListener { /* ... */ }
///
/// let manager = SaTokenConfig::builder()
/// .storage(Arc::new(MemoryStorage::new()))
/// .register_listener(Arc::new(MyListener))
/// .build();
/// ```
pub fn register_listener(mut self, listener: Arc<dyn SaTokenListener>) -> Self {
self.listeners.push(listener);
self
}
/// 构建 SaTokenManager(需要先设置 storage)
///
/// 自动完成以下操作:
/// 1. 创建 SaTokenManager
/// 2. 注册所有事件监听器
/// 3. 初始化 StpUtil
///
/// Auto-complete the following operations:
/// 1. Create SaTokenManager
/// 2. Register all event listeners
/// 3. Initialize StpUtil
///
/// # Panics
/// 如果未设置 storage,会 panic
///
/// # 示例
/// ```rust,ignore
/// use std::sync::Arc;
/// use sa_token_core::SaTokenConfig;
/// use sa_token_storage_memory::MemoryStorage;
///
/// // 一行代码完成所有初始化!
/// // Complete all initialization in one line!
/// SaTokenConfig::builder()
/// .storage(Arc::new(MemoryStorage::new()))
/// .timeout(7200)
/// .register_listener(Arc::new(MyListener))
/// .build(); // 自动初始化 StpUtil!
/// ```
pub fn build(self) -> crate::SaTokenManager {
let storage = self.storage.expect("Storage must be set before building SaTokenManager. Use .storage() method.");
let manager = crate::SaTokenManager::new(storage, self.config);
// 同步注册所有监听器
// Register all listeners synchronously
if !self.listeners.is_empty() {
let event_bus = manager.event_bus();
for listener in self.listeners {
event_bus.register(listener);
}
}
// 自动初始化 StpUtil
// Auto-initialize StpUtil
crate::StpUtil::init_manager(manager.clone());
manager
}
/// 仅构建配置(不创建 Manager)
pub fn build_config(self) -> SaTokenConfig {
self.config
}
}