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