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 = format!("sa: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 = format!("sa: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    pub async fn set_permissions(
457        login_id: impl LoginId,
458        permissions: Vec<String>,
459    ) -> SaTokenResult<()> {
460        let manager = Self::get_manager();
461        let mut map = manager.user_permissions.write().await;
462        map.insert(login_id.to_login_id(), permissions);
463        Ok(())
464    }
465    
466    /// 为用户添加单个权限
467    pub async fn add_permission(
468        login_id: impl LoginId,
469        permission: impl Into<String>,
470    ) -> SaTokenResult<()> {
471        let manager = Self::get_manager();
472        let mut map = manager.user_permissions.write().await;
473        let login_id_str = login_id.to_login_id();
474        let permissions = map.entry(login_id_str).or_insert_with(Vec::new);
475        let perm = permission.into();
476        if !permissions.contains(&perm) {
477            permissions.push(perm);
478        }
479        Ok(())
480    }
481    
482    /// 移除用户的某个权限
483    pub async fn remove_permission(
484        login_id: impl LoginId,
485        permission: &str,
486    ) -> SaTokenResult<()> {
487        let manager = Self::get_manager();
488        let mut map = manager.user_permissions.write().await;
489        if let Some(permissions) = map.get_mut(&login_id.to_login_id()) {
490            permissions.retain(|p| p != permission);
491        }
492        Ok(())
493    }
494    
495    /// 清除用户的所有权限
496    pub async fn clear_permissions(login_id: impl LoginId) -> SaTokenResult<()> {
497        let manager = Self::get_manager();
498        let mut map = manager.user_permissions.write().await;
499        map.remove(&login_id.to_login_id());
500        Ok(())
501    }
502    
503    /// 获取用户的所有权限
504    pub async fn get_permissions(login_id: impl LoginId) -> Vec<String> {
505        let manager = Self::get_manager();
506        let map = manager.user_permissions.read().await;
507        map.get(&login_id.to_login_id()).cloned().unwrap_or_default()
508    }
509    
510    /// 检查用户是否拥有指定权限
511    pub async fn has_permission(
512        login_id: impl LoginId,
513        permission: &str,
514    ) -> bool {
515        let manager = Self::get_manager();
516        let map = manager.user_permissions.read().await;
517        if let Some(permissions) = map.get(&login_id.to_login_id()) {
518            // 精确匹配
519            if permissions.contains(&permission.to_string()) {
520                return true;
521            }
522            
523            // 通配符匹配(例如 admin:* 匹配 admin:read)
524            for perm in permissions {
525                if perm.ends_with(":*") {
526                    let prefix = &perm[..perm.len() - 2];
527                    if permission.starts_with(prefix) {
528                        return true;
529                    }
530                }
531            }
532        }
533        false
534    }
535    
536    /// 检查用户是否拥有所有指定权限(AND 逻辑)
537    pub async fn has_all_permissions(
538        login_id: impl LoginId,
539        permissions: &[&str],
540    ) -> bool {
541        let login_id_str = login_id.to_login_id();
542        for permission in permissions {
543            if !Self::has_permission(&login_id_str, permission).await {
544                return false;
545            }
546        }
547        true
548    }
549    
550    /// 检查用户是否拥有所有指定权限(别名,AND 逻辑)
551    pub async fn has_permissions_and(
552        login_id: impl LoginId,
553        permissions: &[&str],
554    ) -> bool {
555        Self::has_all_permissions(login_id, permissions).await
556    }
557    
558    /// 检查用户是否拥有任一指定权限(OR 逻辑)
559    pub async fn has_any_permission(
560        login_id: impl LoginId,
561        permissions: &[&str],
562    ) -> bool {
563        let login_id_str = login_id.to_login_id();
564        for permission in permissions {
565            if Self::has_permission(&login_id_str, permission).await {
566                return true;
567            }
568        }
569        false
570    }
571    
572    /// 检查用户是否拥有任一指定权限(别名,OR 逻辑)
573    pub async fn has_permissions_or(
574        login_id: impl LoginId,
575        permissions: &[&str],
576    ) -> bool {
577        Self::has_any_permission(login_id, permissions).await
578    }
579    
580    /// 检查权限,如果没有则抛出异常
581    pub async fn check_permission(
582        login_id: impl LoginId,
583        permission: &str,
584    ) -> SaTokenResult<()> {
585        if !Self::has_permission(login_id, permission).await {
586            return Err(SaTokenError::PermissionDeniedDetail(permission.to_string()));
587        }
588        Ok(())
589    }
590}
591
592// ==================== 角色管理 ====================
593
594impl StpUtil {
595    /// 为用户设置角色
596    pub async fn set_roles(
597        login_id: impl LoginId,
598        roles: Vec<String>,
599    ) -> SaTokenResult<()> {
600        let manager = Self::get_manager();
601        let mut map = manager.user_roles.write().await;
602        map.insert(login_id.to_login_id(), roles);
603        Ok(())
604    }
605    
606    /// 为用户添加单个角色
607    pub async fn add_role(
608        login_id: impl LoginId,
609        role: impl Into<String>,
610    ) -> SaTokenResult<()> {
611        let manager = Self::get_manager();
612        let mut map = manager.user_roles.write().await;
613        let login_id_str = login_id.to_login_id();
614        let roles = map.entry(login_id_str).or_insert_with(Vec::new);
615        let r = role.into();
616        if !roles.contains(&r) {
617            roles.push(r);
618        }
619        Ok(())
620    }
621    
622    /// 移除用户的某个角色
623    pub async fn remove_role(
624        login_id: impl LoginId,
625        role: &str,
626    ) -> SaTokenResult<()> {
627        let manager = Self::get_manager();
628        let mut map = manager.user_roles.write().await;
629        if let Some(roles) = map.get_mut(&login_id.to_login_id()) {
630            roles.retain(|r| r != role);
631        }
632        Ok(())
633    }
634    
635    /// 清除用户的所有角色
636    pub async fn clear_roles(login_id: impl LoginId) -> SaTokenResult<()> {
637        let manager = Self::get_manager();
638        let mut map = manager.user_roles.write().await;
639        map.remove(&login_id.to_login_id());
640        Ok(())
641    }
642    
643    /// 获取用户的所有角色
644    pub async fn get_roles(login_id: impl LoginId) -> Vec<String> {
645        let manager = Self::get_manager();
646        let map = manager.user_roles.read().await;
647        map.get(&login_id.to_login_id()).cloned().unwrap_or_default()
648    }
649    
650    /// 检查用户是否拥有指定角色
651    pub async fn has_role(
652        login_id: impl LoginId,
653        role: &str,
654    ) -> bool {
655        let manager = Self::get_manager();
656        let map = manager.user_roles.read().await;
657        if let Some(roles) = map.get(&login_id.to_login_id()) {
658            roles.contains(&role.to_string())
659        } else {
660            false
661        }
662    }
663    
664    /// 检查用户是否拥有所有指定角色(AND 逻辑)
665    pub async fn has_all_roles(
666        login_id: impl LoginId,
667        roles: &[&str],
668    ) -> bool {
669        let login_id_str = login_id.to_login_id();
670        for role in roles {
671            if !Self::has_role(&login_id_str, role).await {
672                return false;
673            }
674        }
675        true
676    }
677    
678    /// 检查用户是否拥有所有指定角色(别名,AND 逻辑)
679    pub async fn has_roles_and(
680        login_id: impl LoginId,
681        roles: &[&str],
682    ) -> bool {
683        Self::has_all_roles(login_id, roles).await
684    }
685    
686    /// 检查用户是否拥有任一指定角色(OR 逻辑)
687    pub async fn has_any_role(
688        login_id: impl LoginId,
689        roles: &[&str],
690    ) -> bool {
691        let login_id_str = login_id.to_login_id();
692        for role in roles {
693            if Self::has_role(&login_id_str, role).await {
694                return true;
695            }
696        }
697        false
698    }
699    
700    /// 检查用户是否拥有任一指定角色(别名,OR 逻辑)
701    pub async fn has_roles_or(
702        login_id: impl LoginId,
703        roles: &[&str],
704    ) -> bool {
705        Self::has_any_role(login_id, roles).await
706    }
707    
708    /// 检查角色,如果没有则抛出异常
709    pub async fn check_role(
710        login_id: impl LoginId,
711        role: &str,
712    ) -> SaTokenResult<()> {
713        if !Self::has_role(login_id, role).await {
714            return Err(SaTokenError::RoleDenied(role.to_string()));
715        }
716        Ok(())
717    }
718}
719
720// ==================== 扩展工具方法 ====================
721
722impl StpUtil {
723    /// 批量踢人下线
724    pub async fn kick_out_batch<T: LoginId>(
725        login_ids: &[T],
726    ) -> SaTokenResult<Vec<Result<(), SaTokenError>>> {
727        let manager = Self::get_manager();
728        let mut results = Vec::new();
729        for login_id in login_ids {
730            results.push(manager.kick_out(&login_id.to_login_id()).await);
731        }
732        Ok(results)
733    }
734    
735    /// 获取 token 剩余有效时间(秒)
736    pub async fn get_token_timeout(token: &TokenValue) -> SaTokenResult<Option<i64>> {
737        let manager = Self::get_manager();
738        let token_info = manager.get_token_info(token).await?;
739        
740        if let Some(expire_time) = token_info.expire_time {
741            let now = chrono::Utc::now();
742            let duration = expire_time.signed_duration_since(now);
743            Ok(Some(duration.num_seconds()))
744        } else {
745            Ok(None) // 永久有效
746        }
747    }
748    
749    /// 续期 token(重置过期时间)
750    pub async fn renew_timeout(
751        token: &TokenValue,
752        timeout_seconds: i64,
753    ) -> SaTokenResult<()> {
754        let manager = Self::get_manager();
755        let mut token_info = manager.get_token_info(token).await?;
756        
757        // 设置新的过期时间
758        let new_expire_time = chrono::Utc::now() + chrono::Duration::seconds(timeout_seconds);
759        token_info.expire_time = Some(new_expire_time);
760        
761        // 保存更新后的 token 信息
762        let key = format!("sa:token:{}", token.as_str());
763        let value = serde_json::to_string(&token_info)
764            .map_err(SaTokenError::SerializationError)?;
765        
766        let timeout = std::time::Duration::from_secs(timeout_seconds as u64);
767        manager.storage.set(&key, &value, Some(timeout)).await
768            .map_err(|e| SaTokenError::StorageError(e.to_string()))?;
769        
770        Ok(())
771    }
772    
773    // ==================== 额外数据操作 | Extra Data Operations ====================
774    
775    /// 设置 Token 的额外数据 | Set extra data for token
776    /// 
777    /// # 参数 | Arguments
778    /// * `token` - Token值 | Token value
779    /// * `extra_data` - 额外数据 | Extra data
780    pub async fn set_extra_data(
781        token: &TokenValue,
782        extra_data: serde_json::Value,
783    ) -> SaTokenResult<()> {
784        let manager = Self::get_manager();
785        let mut token_info = manager.get_token_info(token).await?;
786        token_info.extra_data = Some(extra_data);
787        
788        let key = format!("sa:token:{}", token.as_str());
789        let value = serde_json::to_string(&token_info)
790            .map_err(SaTokenError::SerializationError)?;
791        
792        manager.storage.set(&key, &value, manager.config.timeout_duration()).await
793            .map_err(|e| SaTokenError::StorageError(e.to_string()))?;
794        
795        Ok(())
796    }
797    
798    /// 获取 Token 的额外数据 | Get extra data from token
799    /// 
800    /// # 参数 | Arguments
801    /// * `token` - Token值 | Token value
802    pub async fn get_extra_data(token: &TokenValue) -> SaTokenResult<Option<serde_json::Value>> {
803        let manager = Self::get_manager();
804        let token_info = manager.get_token_info(token).await?;
805        Ok(token_info.extra_data)
806    }
807    
808    // ==================== 链式调用 | Chain Call ====================
809    
810    /// 创建 Token 构建器,用于链式调用 | Create token builder for chain calls
811    /// 
812    /// # 示例 | Example
813    /// ```rust,ignore
814    /// use serde_json::json;
815    /// 
816    /// // 链式调用示例
817    /// let token = StpUtil::builder("user_123")
818    ///     .extra_data(json!({"ip": "192.168.1.1"}))
819    ///     .device("pc")
820    ///     .login_type("admin")
821    ///     .login()
822    ///     .await?;
823    /// ```
824    pub fn builder(login_id: impl LoginId) -> TokenBuilder {
825        TokenBuilder::new(login_id.to_login_id())
826    }
827}
828
829/// Token 构建器 - 支持链式调用 | Token Builder - Supports chain calls
830pub struct TokenBuilder {
831    login_id: String,
832    extra_data: Option<serde_json::Value>,
833    device: Option<String>,
834    login_type: Option<String>,
835}
836
837impl TokenBuilder {
838    /// 创建新的 Token 构建器 | Create new token builder
839    pub fn new(login_id: String) -> Self {
840        Self {
841            login_id,
842            extra_data: None,
843            device: None,
844            login_type: None,
845        }
846    }
847    
848    /// 设置额外数据 | Set extra data
849    pub fn extra_data(mut self, data: serde_json::Value) -> Self {
850        self.extra_data = Some(data);
851        self
852    }
853    
854    /// 设置设备信息 | Set device info
855    pub fn device(mut self, device: impl Into<String>) -> Self {
856        self.device = Some(device.into());
857        self
858    }
859    
860    /// 设置登录类型 | Set login type
861    pub fn login_type(mut self, login_type: impl Into<String>) -> Self {
862        self.login_type = Some(login_type.into());
863        self
864    }
865    
866    /// 执行登录操作 | Execute login
867    /// 
868    /// 如果不提供 login_id 参数,则使用构建器中的 login_id
869    pub async fn login<T: LoginId>(self, login_id: Option<T>) -> SaTokenResult<TokenValue> {
870        let manager = StpUtil::get_manager();
871        
872        // 登录获取 token,使用传入的 login_id 或构建器中的 login_id
873        let final_login_id = match login_id {
874            Some(id) => id.to_login_id(),
875            None => self.login_id,
876        };
877        let token = manager.login(final_login_id).await?;
878        
879        // 获取 token 信息并修改
880        let mut token_info = manager.get_token_info(&token).await?;
881        
882        // 设置额外属性
883        if let Some(data) = self.extra_data {
884            token_info.extra_data = Some(data);
885        }
886        
887        if let Some(device) = self.device {
888            token_info.device = Some(device);
889        }
890        
891        if let Some(login_type) = self.login_type {
892            token_info.login_type = login_type;
893        }
894        
895        // 保存更新后的 token 信息
896        let key = format!("sa:token:{}", token.as_str());
897        let value = serde_json::to_string(&token_info)
898            .map_err(SaTokenError::SerializationError)?;
899        
900        manager.storage.set(&key, &value, manager.config.timeout_duration()).await
901            .map_err(|e| SaTokenError::StorageError(e.to_string()))?;
902        
903        Ok(token)
904    }
905}
906
907#[cfg(test)]
908mod tests {
909    use super::*;
910    
911    #[test]
912    fn test_token_format_validation() {
913        assert!(StpUtil::is_valid_token_format("1234567890abcdef"));
914        assert!(!StpUtil::is_valid_token_format(""));
915        assert!(!StpUtil::is_valid_token_format("short"));
916    }
917    
918    #[test]
919    fn test_create_token() {
920        let token = StpUtil::create_token("test-token-123");
921        assert_eq!(token.as_str(), "test-token-123");
922    }
923}