Skip to main content

sa_token_core/
config.rs

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