Skip to main content

sa_token_core/
util.rs

1// Author: 金书记
2//
3//! StpUtil - sa-token 便捷工具类
4//! 
5//! 提供类似 Java 版 StpUtil 的静态方法,方便进行认证和权限操作
6//! 
7//! ## 使用示例
8//! 
9//! ```rust,ignore
10//! use sa_token_core::StpUtil;
11//! 
12//! // 初始化全局 Manager(应用启动时调用一次)
13//! StpUtil::init_manager(manager);
14//! 
15//! // 之后就可以直接使用,支持多种 ID 类型
16//! let token = StpUtil::login("user_123").await?;  // 字符串 ID
17//! let token = StpUtil::login(10001).await?;       // 数字 ID (i32)
18//! let token = StpUtil::login(10001_i64).await?;   // 数字 ID (i64)
19//! 
20//! StpUtil::set_permissions(10001, vec!["user:list".to_string()]).await?;
21//! ```
22
23use std::sync::Arc;
24use std::fmt::Display;
25use once_cell::sync::OnceCell;
26use crate::{SaTokenManager, SaTokenResult, SaTokenError};
27use crate::token::{TokenValue, TokenInfo};
28use crate::session::SaSession;
29use crate::context::SaTokenContext;
30use crate::event::{SaTokenEventBus, SaTokenListener};
31
32/// 全局 SaTokenManager 实例
33static GLOBAL_MANAGER: OnceCell<Arc<SaTokenManager>> = OnceCell::new();
34
35/// LoginId trait - 支持任何可以转换为字符串的类型作为登录 ID
36/// 
37/// 自动实现了 String, &str, i32, i64, u32, u64 等常用类型
38pub trait LoginId {
39    fn to_login_id(&self) -> String;
40}
41
42// 为所有实现了 Display 的类型自动实现 LoginId
43impl<T: Display> LoginId for T {
44    fn to_login_id(&self) -> String {
45        self.to_string()
46    }
47}
48
49/// StpUtil - 权限认证工具类
50/// 
51/// 提供便捷的认证和授权操作方法,类似于 Java 版 sa-token 的 StpUtil
52pub struct StpUtil;
53
54impl StpUtil {
55    // ==================== 初始化 ====================
56    
57    /// 初始化全局 SaTokenManager(应用启动时调用一次)
58    /// 
59    /// # 示例
60    /// ```rust,ignore
61    /// let manager = SaTokenConfig::builder()
62    ///     .storage(Arc::new(MemoryStorage::new()))
63    ///     .build();
64    /// StpUtil::init_manager(manager);
65    /// ```
66    pub fn init_manager(manager: SaTokenManager) {
67        GLOBAL_MANAGER.set(Arc::new(manager))
68            .unwrap_or_else(|_| panic!("StpUtil manager already initialized"));
69    }
70    
71    /// 获取全局 Manager
72    fn get_manager() -> &'static Arc<SaTokenManager> {
73        GLOBAL_MANAGER.get()
74            .expect("StpUtil not initialized. Call StpUtil::init_manager() first.")
75    }
76    
77    /// 获取事件总线,用于注册监听器
78    /// 
79    /// # 示例
80    /// ```rust,ignore
81    /// use sa_token_core::{StpUtil, SaTokenListener};
82    /// use async_trait::async_trait;
83    /// 
84    /// struct MyListener;
85    /// 
86    /// #[async_trait]
87    /// impl SaTokenListener for MyListener {
88    ///     async fn on_login(&self, login_id: &str, token: &str, login_type: &str) {
89    ///         println!("用户 {} 登录了", login_id);
90    ///     }
91    /// }
92    /// 
93    /// // 注册监听器
94    /// StpUtil::event_bus().register(Arc::new(MyListener)).await;
95    /// ```
96    pub fn event_bus() -> &'static SaTokenEventBus {
97        &Self::get_manager().event_bus
98    }
99    
100    /// 注册事件监听器(便捷方法)
101    /// 
102    /// # 示例
103    /// ```rust,ignore
104    /// StpUtil::register_listener(Arc::new(MyListener)).await;
105    /// ```
106    pub fn register_listener(listener: Arc<dyn SaTokenListener>) {
107        Self::event_bus().register(listener);
108    }
109    
110    // ==================== 登录相关 ====================
111    
112    /// 会话登录
113    /// 
114    /// # 示例
115    /// ```rust,ignore
116    /// // 支持字符串 ID
117    /// let token = StpUtil::login("user_123").await?;
118    /// 
119    /// // 支持数字 ID
120    /// let token = StpUtil::login(10001).await?;
121    /// let token = StpUtil::login(10001_i64).await?;
122    /// ```
123    pub async fn login(login_id: impl LoginId) -> SaTokenResult<TokenValue> {
124        Self::get_manager().login(login_id.to_login_id()).await
125    }
126
127    pub async fn login_with_type(login_id: impl LoginId, _login_type: impl Into<String>) -> SaTokenResult<TokenValue> {
128        Self::get_manager().login(login_id.to_login_id()).await
129    }
130    
131    /// 登录并设置额外数据 | Login with extra data
132    /// 
133    /// # 参数 | Arguments
134    /// * `login_id` - 登录ID | Login ID
135    /// * `extra_data` - 额外数据 | Extra data
136    pub async fn login_with_extra(
137        login_id: impl LoginId,
138        extra_data: serde_json::Value,
139    ) -> SaTokenResult<TokenValue> {
140        Self::get_manager().login_with_options(
141            login_id.to_login_id(),
142            None,    // login_type
143            None,    // device
144            Some(extra_data),
145            None,    // nonce
146            None,    // expire_time
147        ).await
148    }
149    
150    /// 会话登录(带 manager 参数的版本,向后兼容)
151    pub async fn login_with_manager(
152        manager: &SaTokenManager,
153        login_id: impl Into<String>,
154    ) -> SaTokenResult<TokenValue> {
155        manager.login(login_id).await
156    }
157    
158    /// 会话登出
159    pub async fn logout(token: &TokenValue) -> SaTokenResult<()> {
160        tracing::debug!("开始执行 logout,token: {}", token);
161        let result = Self::get_manager().logout(token).await;
162        match &result {
163            Ok(_) => tracing::debug!("logout 执行成功,token: {}", token),
164            Err(e) => tracing::debug!("logout 执行失败,token: {}, 错误: {}", token, e),
165        }
166        result
167    }
168    
169    pub async fn logout_with_manager(
170        manager: &SaTokenManager,
171        token: &TokenValue,
172    ) -> SaTokenResult<()> {
173        manager.logout(token).await
174    }
175    
176    /// 踢人下线(根据登录ID)
177    pub async fn kick_out(login_id: impl LoginId) -> SaTokenResult<()> {
178        Self::get_manager().kick_out(&login_id.to_login_id()).await
179    }
180    
181    pub async fn kick_out_with_manager(
182        manager: &SaTokenManager,
183        login_id: &str,
184    ) -> SaTokenResult<()> {
185        manager.kick_out(login_id).await
186    }
187    
188    /// 强制登出(根据登录ID)
189    pub async fn logout_by_login_id(login_id: impl LoginId) -> SaTokenResult<()> {
190        Self::get_manager().logout_by_login_id(&login_id.to_login_id()).await
191    }
192    
193    /// 根据 token 登出(别名方法,更直观)
194    pub async fn logout_by_token(token: &TokenValue) -> SaTokenResult<()> {
195        Self::logout(token).await
196    }
197    
198    // ==================== 当前会话操作(无参数,从上下文获取)====================
199    
200    /// 获取当前请求的 token(无参数,从上下文获取)
201    /// 
202    /// # 示例
203    /// ```rust,ignore
204    /// // 在请求处理函数中
205    /// let token = StpUtil::get_token_value()?;
206    /// ```
207    pub fn get_token_value() -> SaTokenResult<TokenValue> {
208        let ctx = SaTokenContext::try_current().ok_or(SaTokenError::NotLogin)?;
209        ctx.token.ok_or(SaTokenError::NotLogin)
210    }
211    
212    /// 当前会话登出(无参数,从上下文获取 token)
213    /// 
214    /// # 示例
215    /// ```rust,ignore
216    /// // 在请求处理函数中
217    /// StpUtil::logout_current().await?;
218    /// ```
219    pub async fn logout_current() -> SaTokenResult<()> {
220        let token = Self::get_token_value()?;
221        tracing::debug!("成功获取 token: {}", token);
222        
223        let result = Self::logout(&token).await;
224        match &result {
225            Ok(_) => tracing::debug!("logout_current 执行成功,token: {}", token),
226            Err(e) => tracing::debug!("logout_current 执行失败,token: {}, 错误: {}", token, e),
227        }
228        result
229    }
230    
231    /// 检查当前会话是否登录(无参数,返回 bool)
232    /// 
233    /// # 示例
234    /// ```rust,ignore
235    /// // 在请求处理函数中
236    /// if StpUtil::is_login_current() {
237    ///     println!("当前用户已登录");
238    /// }
239    /// ```
240    pub fn is_login_current() -> bool {
241        if let Ok(_token) = Self::get_token_value() {
242            // 注意:这里使用同步检查,只检查上下文中是否有 token
243            // 如果需要异步验证,需要使用 is_login(&token).await
244            true
245        } else {
246            false
247        }
248    }
249    
250    /// 检查当前会话登录状态,未登录则抛出异常(无参数)
251    /// 
252    /// # 示例
253    /// ```rust,ignore
254    /// // 在请求处理函数中
255    /// StpUtil::check_login_current()?;
256    /// ```
257    pub fn check_login_current() -> SaTokenResult<()> {
258        Self::get_token_value()?;
259        Ok(())
260    }
261    
262    /// 获取当前会话的 login_id(String 类型,无参数)
263    /// 
264    /// # 示例
265    /// ```rust,ignore
266    /// // 在请求处理函数中
267    /// let login_id = StpUtil::get_login_id_as_string().await?;
268    /// ```
269    pub async fn get_login_id_as_string() -> SaTokenResult<String> {
270        let token = Self::get_token_value()?;
271        Self::get_login_id(&token).await
272    }
273    
274    /// 获取当前会话的 login_id(i64 类型,无参数)
275    /// 
276    /// # 示例
277    /// ```rust,ignore
278    /// // 在请求处理函数中
279    /// let user_id = StpUtil::get_login_id_as_long().await?;
280    /// ```
281    pub async fn get_login_id_as_long() -> SaTokenResult<i64> {
282        let login_id_str = Self::get_login_id_as_string().await?;
283        login_id_str.parse::<i64>()
284            .map_err(|_| SaTokenError::LoginIdNotNumber)
285    }
286    
287    /// 获取当前会话的 token 信息(无参数)
288    /// 
289    /// # 示例
290    /// ```rust,ignore
291    /// // 在请求处理函数中
292    /// let token_info = StpUtil::get_token_info_current()?;
293    /// println!("Token 创建时间: {:?}", token_info.create_time);
294    /// ```
295    pub fn get_token_info_current() -> SaTokenResult<Arc<TokenInfo>> {
296        let ctx = SaTokenContext::try_current().ok_or(SaTokenError::NotLogin)?;
297        ctx.token_info.ok_or(SaTokenError::NotLogin)
298    }
299    
300    // ==================== Token 验证 ====================
301    
302    /// 检查当前 token 是否已登录
303    pub async fn is_login(token: &TokenValue) -> bool {
304        Self::get_manager().is_valid(token).await
305    }
306    
307    /// 根据登录 ID 检查是否已登录
308    /// 
309    /// # 示例
310    /// ```rust,ignore
311    /// let is_logged_in = StpUtil::is_login_by_login_id("user_123").await;
312    /// let is_logged_in = StpUtil::is_login_by_login_id(10001).await;
313    /// ```
314    pub async fn is_login_by_login_id(login_id: impl LoginId) -> bool {
315        match Self::get_token_by_login_id(login_id).await {
316            Ok(token) => Self::is_login(&token).await,
317            Err(_) => false,
318        }
319    }
320    
321    pub async fn is_login_with_manager(
322        manager: &SaTokenManager,
323        token: &TokenValue,
324    ) -> bool {
325        manager.is_valid(token).await
326    }
327    
328    /// 检查当前 token 是否已登录,如果未登录则抛出异常
329    pub async fn check_login(token: &TokenValue) -> SaTokenResult<()> {
330        if !Self::is_login(token).await {
331            return Err(SaTokenError::NotLogin);
332        }
333        Ok(())
334    }
335    
336    /// 获取 token 信息
337    pub async fn get_token_info(token: &TokenValue) -> SaTokenResult<TokenInfo> {
338        Self::get_manager().get_token_info(token).await
339    }
340    
341    /// 获取当前 token 的登录ID
342    pub async fn get_login_id(token: &TokenValue) -> SaTokenResult<String> {
343        let token_info = Self::get_manager().get_token_info(token).await?;
344        Ok(token_info.login_id)
345    }
346    
347    /// 获取当前 token 的登录ID,如果未登录则返回默认值
348    pub async fn get_login_id_or_default(
349        token: &TokenValue,
350        default: impl Into<String>,
351    ) -> String {
352        Self::get_login_id(token)
353            .await
354            .unwrap_or_else(|_| default.into())
355    }
356    
357    /// 根据登录 ID 获取当前用户的 token
358    /// 
359    /// # 示例
360    /// ```rust,ignore
361    /// let token = StpUtil::get_token_by_login_id("user_123").await?;
362    /// let token = StpUtil::get_token_by_login_id(10001).await?;
363    /// ```
364    pub async fn get_token_by_login_id(login_id: impl LoginId) -> SaTokenResult<TokenValue> {
365        let manager = Self::get_manager();
366        let login_id_str = login_id.to_login_id();
367        
368        // 从存储中获取该用户的 token
369        let key = manager.config.make_key("login:token:", &login_id_str);
370        match manager.storage.get(&key).await {
371            Ok(Some(token_str)) => Ok(TokenValue::new(token_str)),
372            Ok(None) => Err(SaTokenError::NotLogin),
373            Err(e) => Err(SaTokenError::StorageError(e.to_string())),
374        }
375    }
376    
377    /// 根据登录 ID 获取所有在线的 token 列表(支持多设备登录)
378    /// 
379    /// # 示例
380    /// ```rust,ignore
381    /// let tokens = StpUtil::get_all_tokens_by_login_id("user_123").await?;
382    /// ```
383    pub async fn get_all_tokens_by_login_id(login_id: impl LoginId) -> SaTokenResult<Vec<TokenValue>> {
384        let manager = Self::get_manager();
385        let login_id_str = login_id.to_login_id();
386        
387        // 从存储中获取该用户的所有 token
388        let key = manager.config.make_key("login:tokens:", &login_id_str);
389        match manager.storage.get(&key).await {
390            Ok(Some(tokens_str)) => {
391                let token_strings: Vec<String> = serde_json::from_str(&tokens_str)
392                    .map_err(SaTokenError::SerializationError)?;
393                Ok(token_strings.into_iter().map(TokenValue::new).collect())
394            }
395            Ok(None) => Ok(Vec::new()),
396            Err(e) => Err(SaTokenError::StorageError(e.to_string())),
397        }
398    }
399    
400    // ==================== Session 会话 ====================
401    
402    /// 获取当前登录账号的 Session
403    pub async fn get_session(login_id: impl LoginId) -> SaTokenResult<SaSession> {
404        Self::get_manager().get_session(&login_id.to_login_id()).await
405    }
406    
407    /// 保存 Session
408    pub async fn save_session(session: &SaSession) -> SaTokenResult<()> {
409        Self::get_manager().save_session(session).await
410    }
411    
412    /// 删除 Session
413    pub async fn delete_session(login_id: impl LoginId) -> SaTokenResult<()> {
414        Self::get_manager().delete_session(&login_id.to_login_id()).await
415    }
416    
417    /// 在 Session 中设置值
418    pub async fn set_session_value<T: serde::Serialize>(
419        login_id: impl LoginId,
420        key: &str,
421        value: T,
422    ) -> SaTokenResult<()> {
423        let manager = Self::get_manager();
424        let login_id_str = login_id.to_login_id();
425        let mut session = manager.get_session(&login_id_str).await?;
426        session.set(key, value)?;
427        manager.save_session(&session).await
428    }
429    
430    /// 从 Session 中获取值
431    pub async fn get_session_value<T: serde::de::DeserializeOwned>(
432        login_id: impl LoginId,
433        key: &str,
434    ) -> SaTokenResult<Option<T>> {
435        let session = Self::get_manager().get_session(&login_id.to_login_id()).await?;
436        Ok(session.get::<T>(key))
437    }
438    
439    // ==================== Token 相关 ====================
440    
441    /// 创建一个新的 token(但不登录)
442    pub fn create_token(token_value: impl Into<String>) -> TokenValue {
443        TokenValue::new(token_value.into())
444    }
445    
446    /// 检查 token 格式是否有效(仅检查格式,不检查是否存在于存储中)
447    pub fn is_valid_token_format(token: &str) -> bool {
448        !token.is_empty() && token.len() >= 16
449    }
450}
451
452// ==================== 权限管理 ====================
453
454impl StpUtil {
455    /// 覆盖设置用户权限列表
456    /// 会完全替换该用户的所有权限
457    pub async fn set_permissions(
458        login_id: impl LoginId,
459        permissions: Vec<String>,
460    ) -> SaTokenResult<()> {
461        Self::get_manager()
462            .set_permissions(&login_id.to_login_id(), permissions)
463            .await
464    }
465
466    /// 为用户追加单个权限(已存在则跳过)
467    pub async fn add_permission(
468        login_id: impl LoginId,
469        permission: impl Into<String>,
470    ) -> SaTokenResult<()> {
471        Self::get_manager()
472            .add_permission(&login_id.to_login_id(), permission.into())
473            .await
474    }
475
476    /// 移除用户的某个权限
477    pub async fn remove_permission(
478        login_id: impl LoginId,
479        permission: &str,
480    ) -> SaTokenResult<()> {
481        Self::get_manager()
482            .remove_permission(&login_id.to_login_id(), permission)
483            .await
484    }
485
486    /// 清除用户的所有权限
487    pub async fn clear_permissions(login_id: impl LoginId) -> SaTokenResult<()> {
488        Self::get_manager()
489            .clear_permissions(&login_id.to_login_id())
490            .await
491    }
492
493    /// 获取用户的所有权限
494    /// 存储异常时返回空列表,保持原有 API 语义(返回 Vec 而非 Result)
495    pub async fn get_permissions(login_id: impl LoginId) -> Vec<String> {
496        Self::get_manager()
497            .get_permissions(&login_id.to_login_id())
498            .await
499            .unwrap_or_default()
500    }
501
502    /// 检查用户是否拥有指定权限
503    /// 支持精确匹配与通配符匹配(如 `admin:*` 匹配 `admin:read`)
504    /// 存储读取失败时按"无权限"处理
505    pub async fn has_permission(
506        login_id: impl LoginId,
507        permission: &str,
508    ) -> bool {
509        let permissions = match Self::get_manager()
510            .get_permissions(&login_id.to_login_id())
511            .await
512        {
513            Ok(list) => list,
514            Err(_) => return false,
515        };
516
517        // 1. 精确匹配
518        if permissions.iter().any(|p| p == permission) {
519            return true;
520        }
521
522        // 2. 通配符匹配:例如 admin:* 匹配 admin:read
523        permissions.iter().any(|perm| {
524            perm.ends_with(":*") && permission.starts_with(&perm[..perm.len() - 2])
525        })
526    }
527    
528    /// 检查用户是否拥有所有指定权限(AND 逻辑)
529    pub async fn has_all_permissions(
530        login_id: impl LoginId,
531        permissions: &[&str],
532    ) -> bool {
533        let login_id_str = login_id.to_login_id();
534        for permission in permissions {
535            if !Self::has_permission(&login_id_str, permission).await {
536                return false;
537            }
538        }
539        true
540    }
541    
542    /// 检查用户是否拥有所有指定权限(别名,AND 逻辑)
543    pub async fn has_permissions_and(
544        login_id: impl LoginId,
545        permissions: &[&str],
546    ) -> bool {
547        Self::has_all_permissions(login_id, permissions).await
548    }
549    
550    /// 检查用户是否拥有任一指定权限(OR 逻辑)
551    pub async fn has_any_permission(
552        login_id: impl LoginId,
553        permissions: &[&str],
554    ) -> bool {
555        let login_id_str = login_id.to_login_id();
556        for permission in permissions {
557            if Self::has_permission(&login_id_str, permission).await {
558                return true;
559            }
560        }
561        false
562    }
563    
564    /// 检查用户是否拥有任一指定权限(别名,OR 逻辑)
565    pub async fn has_permissions_or(
566        login_id: impl LoginId,
567        permissions: &[&str],
568    ) -> bool {
569        Self::has_any_permission(login_id, permissions).await
570    }
571    
572    /// 检查权限,如果没有则抛出异常
573    pub async fn check_permission(
574        login_id: impl LoginId,
575        permission: &str,
576    ) -> SaTokenResult<()> {
577        if !Self::has_permission(login_id, permission).await {
578            return Err(SaTokenError::PermissionDeniedDetail(permission.to_string()));
579        }
580        Ok(())
581    }
582}
583
584// ==================== 角色管理 ====================
585
586impl StpUtil {
587    /// 覆盖设置用户角色列表
588    /// 会完全替换该用户的所有角色
589    pub async fn set_roles(
590        login_id: impl LoginId,
591        roles: Vec<String>,
592    ) -> SaTokenResult<()> {
593        Self::get_manager()
594            .set_roles(&login_id.to_login_id(), roles)
595            .await
596    }
597
598    /// 为用户追加单个角色(已存在则跳过)
599    pub async fn add_role(
600        login_id: impl LoginId,
601        role: impl Into<String>,
602    ) -> SaTokenResult<()> {
603        Self::get_manager()
604            .add_role(&login_id.to_login_id(), role.into())
605            .await
606    }
607
608    /// 移除用户的某个角色
609    pub async fn remove_role(
610        login_id: impl LoginId,
611        role: &str,
612    ) -> SaTokenResult<()> {
613        Self::get_manager()
614            .remove_role(&login_id.to_login_id(), role)
615            .await
616    }
617
618    /// 清除用户的所有角色
619    pub async fn clear_roles(login_id: impl LoginId) -> SaTokenResult<()> {
620        Self::get_manager()
621            .clear_roles(&login_id.to_login_id())
622            .await
623    }
624
625    /// 获取用户的所有角色
626    /// 存储异常时返回空列表,保持原有 API 语义
627    pub async fn get_roles(login_id: impl LoginId) -> Vec<String> {
628        Self::get_manager()
629            .get_roles(&login_id.to_login_id())
630            .await
631            .unwrap_or_default()
632    }
633
634    /// 检查用户是否拥有指定角色(精确匹配)
635    /// 存储读取失败时按"无角色"处理
636    pub async fn has_role(
637        login_id: impl LoginId,
638        role: &str,
639    ) -> bool {
640        match Self::get_manager().get_roles(&login_id.to_login_id()).await {
641            Ok(roles) => roles.iter().any(|r| r == role),
642            Err(_) => false,
643        }
644    }
645    
646    /// 检查用户是否拥有所有指定角色(AND 逻辑)
647    pub async fn has_all_roles(
648        login_id: impl LoginId,
649        roles: &[&str],
650    ) -> bool {
651        let login_id_str = login_id.to_login_id();
652        for role in roles {
653            if !Self::has_role(&login_id_str, role).await {
654                return false;
655            }
656        }
657        true
658    }
659    
660    /// 检查用户是否拥有所有指定角色(别名,AND 逻辑)
661    pub async fn has_roles_and(
662        login_id: impl LoginId,
663        roles: &[&str],
664    ) -> bool {
665        Self::has_all_roles(login_id, roles).await
666    }
667    
668    /// 检查用户是否拥有任一指定角色(OR 逻辑)
669    pub async fn has_any_role(
670        login_id: impl LoginId,
671        roles: &[&str],
672    ) -> bool {
673        let login_id_str = login_id.to_login_id();
674        for role in roles {
675            if Self::has_role(&login_id_str, role).await {
676                return true;
677            }
678        }
679        false
680    }
681    
682    /// 检查用户是否拥有任一指定角色(别名,OR 逻辑)
683    pub async fn has_roles_or(
684        login_id: impl LoginId,
685        roles: &[&str],
686    ) -> bool {
687        Self::has_any_role(login_id, roles).await
688    }
689    
690    /// 检查角色,如果没有则抛出异常
691    pub async fn check_role(
692        login_id: impl LoginId,
693        role: &str,
694    ) -> SaTokenResult<()> {
695        if !Self::has_role(login_id, role).await {
696            return Err(SaTokenError::RoleDenied(role.to_string()));
697        }
698        Ok(())
699    }
700}
701
702// ==================== 扩展工具方法 ====================
703
704impl StpUtil {
705    /// 批量踢人下线
706    pub async fn kick_out_batch<T: LoginId>(
707        login_ids: &[T],
708    ) -> SaTokenResult<Vec<Result<(), SaTokenError>>> {
709        let manager = Self::get_manager();
710        let mut results = Vec::new();
711        for login_id in login_ids {
712            results.push(manager.kick_out(&login_id.to_login_id()).await);
713        }
714        Ok(results)
715    }
716    
717    /// 获取 token 剩余有效时间(秒)
718    pub async fn get_token_timeout(token: &TokenValue) -> SaTokenResult<Option<i64>> {
719        let manager = Self::get_manager();
720        let token_info = manager.get_token_info(token).await?;
721        
722        if let Some(expire_time) = token_info.expire_time {
723            let now = chrono::Utc::now();
724            let duration = expire_time.signed_duration_since(now);
725            Ok(Some(duration.num_seconds()))
726        } else {
727            Ok(None) // 永久有效
728        }
729    }
730    
731    /// 续期 token(重置过期时间)
732    pub async fn renew_timeout(
733        token: &TokenValue,
734        timeout_seconds: i64,
735    ) -> SaTokenResult<()> {
736        let manager = Self::get_manager();
737        let mut token_info = manager.get_token_info(token).await?;
738        
739        // 设置新的过期时间
740        let new_expire_time = chrono::Utc::now() + chrono::Duration::seconds(timeout_seconds);
741        token_info.expire_time = Some(new_expire_time);
742        
743        // 保存更新后的 token 信息
744        let key = manager.config.make_key("token:", token.as_str());
745        let value = serde_json::to_string(&token_info)
746            .map_err(SaTokenError::SerializationError)?;
747        
748        let timeout = std::time::Duration::from_secs(timeout_seconds as u64);
749        manager.storage.set(&key, &value, Some(timeout)).await
750            .map_err(|e| SaTokenError::StorageError(e.to_string()))?;
751        
752        Ok(())
753    }
754    
755    // ==================== 额外数据操作 | Extra Data Operations ====================
756    
757    /// 设置 Token 的额外数据 | Set extra data for token
758    /// 
759    /// # 参数 | Arguments
760    /// * `token` - Token值 | Token value
761    /// * `extra_data` - 额外数据 | Extra data
762    pub async fn set_extra_data(
763        token: &TokenValue,
764        extra_data: serde_json::Value,
765    ) -> SaTokenResult<()> {
766        let manager = Self::get_manager();
767        let mut token_info = manager.get_token_info(token).await?;
768        token_info.extra_data = Some(extra_data);
769        
770        let key = manager.config.make_key("token:", token.as_str());
771        let value = serde_json::to_string(&token_info)
772            .map_err(SaTokenError::SerializationError)?;
773        
774        manager.storage.set(&key, &value, manager.config.timeout_duration()).await
775            .map_err(|e| SaTokenError::StorageError(e.to_string()))?;
776        
777        Ok(())
778    }
779    
780    /// 获取 Token 的额外数据 | Get extra data from token
781    /// 
782    /// # 参数 | Arguments
783    /// * `token` - Token值 | Token value
784    pub async fn get_extra_data(token: &TokenValue) -> SaTokenResult<Option<serde_json::Value>> {
785        let manager = Self::get_manager();
786        let token_info = manager.get_token_info(token).await?;
787        Ok(token_info.extra_data)
788    }
789    
790    // ==================== 链式调用 | Chain Call ====================
791    
792    /// 创建 Token 构建器,用于链式调用 | Create token builder for chain calls
793    /// 
794    /// # 示例 | Example
795    /// ```rust,ignore
796    /// use serde_json::json;
797    /// 
798    /// // 链式调用示例
799    /// let token = StpUtil::builder("user_123")
800    ///     .extra_data(json!({"ip": "192.168.1.1"}))
801    ///     .device("pc")
802    ///     .login_type("admin")
803    ///     .login()
804    ///     .await?;
805    /// ```
806    pub fn builder(login_id: impl LoginId) -> TokenBuilder {
807        TokenBuilder::new(login_id.to_login_id())
808    }
809}
810
811/// Token 构建器 - 支持链式调用 | Token Builder - Supports chain calls
812pub struct TokenBuilder {
813    login_id: String,
814    extra_data: Option<serde_json::Value>,
815    device: Option<String>,
816    login_type: Option<String>,
817}
818
819impl TokenBuilder {
820    /// 创建新的 Token 构建器 | Create new token builder
821    pub fn new(login_id: String) -> Self {
822        Self {
823            login_id,
824            extra_data: None,
825            device: None,
826            login_type: None,
827        }
828    }
829    
830    /// 设置额外数据 | Set extra data
831    pub fn extra_data(mut self, data: serde_json::Value) -> Self {
832        self.extra_data = Some(data);
833        self
834    }
835    
836    /// 设置设备信息 | Set device info
837    pub fn device(mut self, device: impl Into<String>) -> Self {
838        self.device = Some(device.into());
839        self
840    }
841    
842    /// 设置登录类型 | Set login type
843    pub fn login_type(mut self, login_type: impl Into<String>) -> Self {
844        self.login_type = Some(login_type.into());
845        self
846    }
847    
848    /// 执行登录操作 | Execute login
849    /// 
850    /// 如果不提供 login_id 参数,则使用构建器中的 login_id
851    pub async fn login<T: LoginId>(self, login_id: Option<T>) -> SaTokenResult<TokenValue> {
852        let manager = StpUtil::get_manager();
853        
854        // 登录获取 token,使用传入的 login_id 或构建器中的 login_id
855        let final_login_id = match login_id {
856            Some(id) => id.to_login_id(),
857            None => self.login_id,
858        };
859        let token = manager.login(final_login_id).await?;
860        
861        // 获取 token 信息并修改
862        let mut token_info = manager.get_token_info(&token).await?;
863        
864        // 设置额外属性
865        if let Some(data) = self.extra_data {
866            token_info.extra_data = Some(data);
867        }
868        
869        if let Some(device) = self.device {
870            token_info.device = Some(device);
871        }
872        
873        if let Some(login_type) = self.login_type {
874            token_info.login_type = login_type;
875        }
876        
877        // 保存更新后的 token 信息
878        let key = manager.config.make_key("token:", token.as_str());
879        let value = serde_json::to_string(&token_info)
880            .map_err(SaTokenError::SerializationError)?;
881        
882        manager.storage.set(&key, &value, manager.config.timeout_duration()).await
883            .map_err(|e| SaTokenError::StorageError(e.to_string()))?;
884        
885        Ok(token)
886    }
887}
888
889#[cfg(test)]
890mod tests {
891    use super::*;
892    
893    #[test]
894    fn test_token_format_validation() {
895        assert!(StpUtil::is_valid_token_format("1234567890abcdef"));
896        assert!(!StpUtil::is_valid_token_format(""));
897        assert!(!StpUtil::is_valid_token_format("short"));
898    }
899    
900    #[test]
901    fn test_create_token() {
902        let token = StpUtil::create_token("test-token-123");
903        assert_eq!(token.as_str(), "test-token-123");
904    }
905}