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 std::sync::OnceLock;
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 实例(标准库 OnceLock,Rust 1.70+)
33static GLOBAL_MANAGER: OnceLock<Arc<SaTokenManager>> = OnceLock::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(
128        login_id: impl LoginId,
129        login_type: impl Into<String>,
130    ) -> SaTokenResult<TokenValue> {
131        Self::get_manager()
132            .login_with_options(
133                login_id.to_login_id(),
134                Some(login_type.into()),
135                None,
136                None,
137                None,
138                None,
139            )
140            .await
141    }
142
143    /// 登录并设置额外数据 | Login with extra data
144    ///
145    /// # 参数 | Arguments
146    /// * `login_id` - 登录ID | Login ID
147    /// * `extra_data` - 额外数据 | Extra data
148    pub async fn login_with_extra(
149        login_id: impl LoginId,
150        extra_data: serde_json::Value,
151    ) -> SaTokenResult<TokenValue> {
152        Self::get_manager().login_with_options(
153            login_id.to_login_id(),
154            None,    // login_type
155            None,    // device
156            Some(extra_data),
157            None,    // nonce
158            None,    // expire_time
159        ).await
160    }
161
162    /// 会话登录(带 manager 参数的版本,向后兼容)
163    pub async fn login_with_manager(
164        manager: &SaTokenManager,
165        login_id: impl Into<String>,
166    ) -> SaTokenResult<TokenValue> {
167        manager.login(login_id).await
168    }
169
170    /// 会话登出
171    pub async fn logout(token: &TokenValue) -> SaTokenResult<()> {
172        tracing::debug!("开始执行 logout,token: {}", token);
173        let result = Self::get_manager().logout(token).await;
174        match &result {
175            Ok(_) => tracing::debug!("logout 执行成功,token: {}", token),
176            Err(e) => tracing::debug!("logout 执行失败,token: {}, 错误: {}", token, e),
177        }
178        result
179    }
180
181    pub async fn logout_with_manager(
182        manager: &SaTokenManager,
183        token: &TokenValue,
184    ) -> SaTokenResult<()> {
185        manager.logout(token).await
186    }
187
188    /// 踢人下线(根据登录ID)
189    pub async fn kick_out(login_id: impl LoginId) -> SaTokenResult<()> {
190        Self::get_manager().kick_out(&login_id.to_login_id()).await
191    }
192
193    pub async fn kick_out_with_manager(
194        manager: &SaTokenManager,
195        login_id: &str,
196    ) -> SaTokenResult<()> {
197        manager.kick_out(login_id).await
198    }
199
200    /// 强制登出(根据登录ID)
201    pub async fn logout_by_login_id(login_id: impl LoginId) -> SaTokenResult<()> {
202        Self::get_manager().logout_by_login_id(&login_id.to_login_id()).await
203    }
204
205    /// 根据 token 登出(别名方法,更直观)
206    pub async fn logout_by_token(token: &TokenValue) -> SaTokenResult<()> {
207        Self::logout(token).await
208    }
209
210    // ==================== 当前会话操作(无参数,从上下文获取)====================
211
212    /// 获取当前请求的 token(无参数,从上下文获取)
213    ///
214    /// # 示例
215    /// ```rust,ignore
216    /// // 在请求处理函数中
217    /// let token = StpUtil::get_token_value()?;
218    /// ```
219    pub fn get_token_value() -> SaTokenResult<TokenValue> {
220        let ctx = SaTokenContext::try_current().ok_or(SaTokenError::NotLogin)?;
221        ctx.token.ok_or(SaTokenError::NotLogin)
222    }
223
224    /// 当前会话登出(无参数,从上下文获取 token)
225    ///
226    /// # 示例
227    /// ```rust,ignore
228    /// // 在请求处理函数中
229    /// StpUtil::logout_current().await?;
230    /// ```
231    pub async fn logout_current() -> SaTokenResult<()> {
232        let token = Self::get_token_value()?;
233        tracing::debug!("成功获取 token: {}", token);
234
235        let result = Self::logout(&token).await;
236        match &result {
237            Ok(_) => tracing::debug!("logout_current 执行成功,token: {}", token),
238            Err(e) => tracing::debug!("logout_current 执行失败,token: {}, 错误: {}", token, e),
239        }
240        result
241    }
242
243    /// 检查当前会话是否登录(无参数,返回 bool)
244    ///
245    /// # 示例
246    /// ```rust,ignore
247    /// // 在请求处理函数中
248    /// if StpUtil::is_login_current() {
249    ///     println!("当前用户已登录");
250    /// }
251    /// ```
252    pub fn is_login_current() -> bool {
253        if let Ok(_token) = Self::get_token_value() {
254            // 注意:这里使用同步检查,只检查上下文中是否有 token
255            // 如果需要异步验证,需要使用 is_login(&token).await
256            true
257        } else {
258            false
259        }
260    }
261
262    /// 检查当前会话登录状态,未登录则抛出异常(无参数)
263    ///
264    /// # 示例
265    /// ```rust,ignore
266    /// // 在请求处理函数中
267    /// StpUtil::check_login_current()?;
268    /// ```
269    pub fn check_login_current() -> SaTokenResult<()> {
270        Self::get_token_value()?;
271        Ok(())
272    }
273
274    /// 获取当前会话的 login_id(String 类型,无参数)
275    ///
276    /// # 示例
277    /// ```rust,ignore
278    /// // 在请求处理函数中
279    /// let login_id = StpUtil::get_login_id_as_string().await?;
280    /// ```
281    pub async fn get_login_id_as_string() -> SaTokenResult<String> {
282        if let Some(ctx) = SaTokenContext::get_current()
283            && let Some(switch_id) = ctx.switch_login_id {
284                return Ok(switch_id);
285            }
286        let token = Self::get_token_value()?;
287        Self::get_login_id(&token).await
288    }
289
290    /// 获取当前会话的 login_id(i64 类型,无参数)
291    ///
292    /// # 示例
293    /// ```rust,ignore
294    /// // 在请求处理函数中
295    /// let user_id = StpUtil::get_login_id_as_long().await?;
296    /// ```
297    pub async fn get_login_id_as_long() -> SaTokenResult<i64> {
298        let login_id_str = Self::get_login_id_as_string().await?;
299        login_id_str.parse::<i64>()
300            .map_err(|_| SaTokenError::LoginIdNotNumber)
301    }
302
303    /// 获取当前会话的 token 信息(无参数)
304    ///
305    /// # 示例
306    /// ```rust,ignore
307    /// // 在请求处理函数中
308    /// let token_info = StpUtil::get_token_info_current()?;
309    /// println!("Token 创建时间: {:?}", token_info.create_time);
310    /// ```
311    pub fn get_token_info_current() -> SaTokenResult<Arc<TokenInfo>> {
312        let ctx = SaTokenContext::try_current().ok_or(SaTokenError::NotLogin)?;
313        ctx.token_info.ok_or(SaTokenError::NotLogin)
314    }
315
316    // ==================== Token 验证 ====================
317
318    /// 检查当前 token 是否已登录
319    pub async fn is_login(token: &TokenValue) -> bool {
320        Self::get_manager().is_valid(token).await
321    }
322
323    /// 根据登录 ID 检查是否已登录
324    ///
325    /// # 示例
326    /// ```rust,ignore
327    /// let is_logged_in = StpUtil::is_login_by_login_id("user_123").await;
328    /// let is_logged_in = StpUtil::is_login_by_login_id(10001).await;
329    /// ```
330    pub async fn is_login_by_login_id(login_id: impl LoginId) -> bool {
331        match Self::get_token_by_login_id(login_id).await {
332            Ok(token) => Self::is_login(&token).await,
333            Err(_) => false,
334        }
335    }
336
337    pub async fn is_login_with_manager(
338        manager: &SaTokenManager,
339        token: &TokenValue,
340    ) -> bool {
341        manager.is_valid(token).await
342    }
343
344    /// 检查当前 token 是否已登录,如果未登录则抛出异常
345    pub async fn check_login(token: &TokenValue) -> SaTokenResult<()> {
346        if !Self::is_login(token).await {
347            return Err(SaTokenError::NotLogin);
348        }
349        Ok(())
350    }
351
352    /// 获取 token 信息
353    pub async fn get_token_info(token: &TokenValue) -> SaTokenResult<TokenInfo> {
354        Self::get_manager().get_token_info(token).await
355    }
356
357    /// 获取当前 token 的登录ID
358    pub async fn get_login_id(token: &TokenValue) -> SaTokenResult<String> {
359        let token_info = Self::get_manager().get_token_info(token).await?;
360        Ok(token_info.login_id)
361    }
362
363    /// 获取当前 token 的登录ID,如果未登录则返回默认值
364    pub async fn get_login_id_or_default(
365        token: &TokenValue,
366        default: impl Into<String>,
367    ) -> String {
368        Self::get_login_id(token)
369            .await
370            .unwrap_or_else(|_| default.into())
371    }
372
373    /// 根据登录 ID 获取当前用户的 token
374    ///
375    /// # 示例
376    /// ```rust,ignore
377    /// let token = StpUtil::get_token_by_login_id("user_123").await?;
378    /// let token = StpUtil::get_token_by_login_id(10001).await?;
379    /// ```
380    pub async fn get_token_by_login_id(login_id: impl LoginId) -> SaTokenResult<TokenValue> {
381        let manager = Self::get_manager();
382        let login_id_str = login_id.to_login_id();
383
384        // 从存储中获取该用户的 token
385        let key = manager.config.make_key("login:token:", &login_id_str);
386        match manager.storage.get(&key).await {
387            Ok(Some(token_str)) => Ok(TokenValue::new(token_str)),
388            Ok(None) => Err(SaTokenError::NotLogin),
389            Err(e) => Err(SaTokenError::StorageError(e.to_string())),
390        }
391    }
392
393    /// 根据登录 ID 获取所有在线的 token 列表(支持多设备登录)
394    ///
395    /// # 示例
396    /// ```rust,ignore
397    /// let tokens = StpUtil::get_all_tokens_by_login_id("user_123").await?;
398    /// ```
399    pub async fn get_all_tokens_by_login_id(login_id: impl LoginId) -> SaTokenResult<Vec<TokenValue>> {
400        let manager = Self::get_manager();
401        let login_id_str = login_id.to_login_id();
402
403        // 从存储中获取该用户的所有 token
404        let key = manager.config.make_key("login:tokens:", &login_id_str);
405        match manager.storage.get(&key).await {
406            Ok(Some(tokens_str)) => {
407                let token_strings: Vec<String> = serde_json::from_str(&tokens_str)
408                    .map_err(SaTokenError::SerializationError)?;
409                Ok(token_strings.into_iter().map(TokenValue::new).collect())
410            }
411            Ok(None) => Ok(Vec::new()),
412            Err(e) => Err(SaTokenError::StorageError(e.to_string())),
413        }
414    }
415
416    // ==================== Session 会话 ====================
417
418    /// 获取当前登录账号的 Session
419    pub async fn get_session(login_id: impl LoginId) -> SaTokenResult<SaSession> {
420        Self::get_manager().get_session(&login_id.to_login_id()).await
421    }
422
423    /// 保存 Session
424    pub async fn save_session(session: &SaSession) -> SaTokenResult<()> {
425        Self::get_manager().save_session(session).await
426    }
427
428    /// 删除 Session
429    pub async fn delete_session(login_id: impl LoginId) -> SaTokenResult<()> {
430        Self::get_manager().delete_session(&login_id.to_login_id()).await
431    }
432
433    /// 在 Session 中设置值
434    pub async fn set_session_value<T: serde::Serialize>(
435        login_id: impl LoginId,
436        key: &str,
437        value: T,
438    ) -> SaTokenResult<()> {
439        let manager = Self::get_manager();
440        let login_id_str = login_id.to_login_id();
441        let mut session = manager.get_session(&login_id_str).await?;
442        session.set(key, value)?;
443        manager.save_session(&session).await
444    }
445
446    /// 从 Session 中获取值
447    pub async fn get_session_value<T: serde::de::DeserializeOwned>(
448        login_id: impl LoginId,
449        key: &str,
450    ) -> SaTokenResult<Option<T>> {
451        let session = Self::get_manager().get_session(&login_id.to_login_id()).await?;
452        Ok(session.get::<T>(key))
453    }
454
455    // ==================== Token 相关 ====================
456
457    /// 创建一个新的 token(但不登录)
458    pub fn create_token(token_value: impl Into<String>) -> TokenValue {
459        TokenValue::new(token_value.into())
460    }
461
462    /// 检查 token 格式是否有效(仅检查格式,不检查是否存在于存储中)
463    pub fn is_valid_token_format(token: &str) -> bool {
464        !token.is_empty() && token.len() >= 16
465    }
466}
467
468// ==================== 权限管理 ====================
469
470impl StpUtil {
471    /// 覆盖设置用户权限列表
472    /// 会完全替换该用户的所有权限
473    pub async fn set_permissions(
474        login_id: impl LoginId,
475        permissions: Vec<String>,
476    ) -> SaTokenResult<()> {
477        Self::get_manager()
478            .set_permissions(&login_id.to_login_id(), permissions)
479            .await
480    }
481
482    /// 为用户追加单个权限(已存在则跳过)
483    pub async fn add_permission(
484        login_id: impl LoginId,
485        permission: impl Into<String>,
486    ) -> SaTokenResult<()> {
487        Self::get_manager()
488            .add_permission(&login_id.to_login_id(), permission.into())
489            .await
490    }
491
492    /// 移除用户的某个权限
493    pub async fn remove_permission(
494        login_id: impl LoginId,
495        permission: &str,
496    ) -> SaTokenResult<()> {
497        Self::get_manager()
498            .remove_permission(&login_id.to_login_id(), permission)
499            .await
500    }
501
502    /// 清除用户的所有权限
503    pub async fn clear_permissions(login_id: impl LoginId) -> SaTokenResult<()> {
504        Self::get_manager()
505            .clear_permissions(&login_id.to_login_id())
506            .await
507    }
508
509    /// 获取用户的所有权限
510    /// 存储异常时返回空列表,保持原有 API 语义(返回 Vec 而非 Result)
511    pub async fn get_permissions(login_id: impl LoginId) -> Vec<String> {
512        Self::get_manager()
513            .get_permissions(&login_id.to_login_id())
514            .await
515            .unwrap_or_default()
516    }
517
518    /// 检查用户是否拥有指定权限
519    /// 支持精确匹配与通配符匹配(如 `admin:*` 匹配 `admin:read`)
520    /// 存储读取失败时按"无权限"处理
521    pub async fn has_permission(
522        login_id: impl LoginId,
523        permission: &str,
524    ) -> bool {
525        let permissions = match Self::get_manager()
526            .get_permissions(&login_id.to_login_id())
527            .await
528        {
529            Ok(list) => list,
530            Err(_) => return false,
531        };
532
533        // 1. 精确匹配
534        if permissions.iter().any(|p| p == permission) {
535            return true;
536        }
537        // 2. 全局通配符:* 匹配一切
538        if permissions.iter().any(|p| p == "*") {
539            return true;
540        }
541        // 3. 前缀通配符:admin:* 匹配 admin:read
542        permissions.iter().any(|perm| {
543            perm.strip_suffix(":*")
544                .is_some_and(|prefix| permission.starts_with(prefix))
545        })
546    }
547
548    /// 检查用户是否拥有所有指定权限(AND 逻辑)
549    pub async fn has_all_permissions(
550        login_id: impl LoginId,
551        permissions: &[&str],
552    ) -> bool {
553        let login_id_str = login_id.to_login_id();
554        for permission in permissions {
555            if !Self::has_permission(&login_id_str, permission).await {
556                return false;
557            }
558        }
559        true
560    }
561
562    /// 检查用户是否拥有所有指定权限(别名,AND 逻辑)
563    pub async fn has_permissions_and(
564        login_id: impl LoginId,
565        permissions: &[&str],
566    ) -> bool {
567        Self::has_all_permissions(login_id, permissions).await
568    }
569
570    /// 检查用户是否拥有任一指定权限(OR 逻辑)
571    pub async fn has_any_permission(
572        login_id: impl LoginId,
573        permissions: &[&str],
574    ) -> bool {
575        let login_id_str = login_id.to_login_id();
576        for permission in permissions {
577            if Self::has_permission(&login_id_str, permission).await {
578                return true;
579            }
580        }
581        false
582    }
583
584    /// 检查用户是否拥有任一指定权限(别名,OR 逻辑)
585    pub async fn has_permissions_or(
586        login_id: impl LoginId,
587        permissions: &[&str],
588    ) -> bool {
589        Self::has_any_permission(login_id, permissions).await
590    }
591
592    /// 检查权限,如果没有则抛出异常
593    pub async fn check_permission(
594        login_id: impl LoginId,
595        permission: &str,
596    ) -> SaTokenResult<()> {
597        if !Self::has_permission(login_id, permission).await {
598            return Err(SaTokenError::PermissionDeniedDetail(permission.to_string()));
599        }
600        Ok(())
601    }
602}
603
604// ==================== 角色管理 ====================
605
606impl StpUtil {
607    /// 覆盖设置用户角色列表
608    /// 会完全替换该用户的所有角色
609    pub async fn set_roles(
610        login_id: impl LoginId,
611        roles: Vec<String>,
612    ) -> SaTokenResult<()> {
613        Self::get_manager()
614            .set_roles(&login_id.to_login_id(), roles)
615            .await
616    }
617
618    /// 为用户追加单个角色(已存在则跳过)
619    pub async fn add_role(
620        login_id: impl LoginId,
621        role: impl Into<String>,
622    ) -> SaTokenResult<()> {
623        Self::get_manager()
624            .add_role(&login_id.to_login_id(), role.into())
625            .await
626    }
627
628    /// 移除用户的某个角色
629    pub async fn remove_role(
630        login_id: impl LoginId,
631        role: &str,
632    ) -> SaTokenResult<()> {
633        Self::get_manager()
634            .remove_role(&login_id.to_login_id(), role)
635            .await
636    }
637
638    /// 清除用户的所有角色
639    pub async fn clear_roles(login_id: impl LoginId) -> SaTokenResult<()> {
640        Self::get_manager()
641            .clear_roles(&login_id.to_login_id())
642            .await
643    }
644
645    /// 获取用户的所有角色
646    /// 存储异常时返回空列表,保持原有 API 语义
647    pub async fn get_roles(login_id: impl LoginId) -> Vec<String> {
648        Self::get_manager()
649            .get_roles(&login_id.to_login_id())
650            .await
651            .unwrap_or_default()
652    }
653
654    /// 检查用户是否拥有指定角色(精确匹配)
655    /// 存储读取失败时按"无角色"处理
656    pub async fn has_role(
657        login_id: impl LoginId,
658        role: &str,
659    ) -> bool {
660        match Self::get_manager().get_roles(&login_id.to_login_id()).await {
661            Ok(roles) => roles.iter().any(|r| r == role),
662            Err(_) => false,
663        }
664    }
665
666    /// 检查用户是否拥有所有指定角色(AND 逻辑)
667    pub async fn has_all_roles(
668        login_id: impl LoginId,
669        roles: &[&str],
670    ) -> bool {
671        let login_id_str = login_id.to_login_id();
672        for role in roles {
673            if !Self::has_role(&login_id_str, role).await {
674                return false;
675            }
676        }
677        true
678    }
679
680    /// 检查用户是否拥有所有指定角色(别名,AND 逻辑)
681    pub async fn has_roles_and(
682        login_id: impl LoginId,
683        roles: &[&str],
684    ) -> bool {
685        Self::has_all_roles(login_id, roles).await
686    }
687
688    /// 检查用户是否拥有任一指定角色(OR 逻辑)
689    pub async fn has_any_role(
690        login_id: impl LoginId,
691        roles: &[&str],
692    ) -> bool {
693        let login_id_str = login_id.to_login_id();
694        for role in roles {
695            if Self::has_role(&login_id_str, role).await {
696                return true;
697            }
698        }
699        false
700    }
701
702    /// 检查用户是否拥有任一指定角色(别名,OR 逻辑)
703    pub async fn has_roles_or(
704        login_id: impl LoginId,
705        roles: &[&str],
706    ) -> bool {
707        Self::has_any_role(login_id, roles).await
708    }
709
710    /// 检查角色,如果没有则抛出异常
711    pub async fn check_role(
712        login_id: impl LoginId,
713        role: &str,
714    ) -> SaTokenResult<()> {
715        if !Self::has_role(login_id, role).await {
716            return Err(SaTokenError::RoleDenied(role.to_string()));
717        }
718        Ok(())
719    }
720}
721
722// ==================== 封禁(disable) ====================
723
724impl StpUtil {
725    /// 封禁账号(默认服务 login)
726    pub async fn disable(login_id: impl LoginId, time: i64) -> SaTokenResult<()> {
727        Self::get_manager()
728            .disable(&login_id.to_login_id(), time)
729            .await
730    }
731
732    /// 封禁账号指定服务与等级
733    pub async fn disable_level(
734        login_id: impl LoginId,
735        service: &str,
736        level: i32,
737        time: i64,
738    ) -> SaTokenResult<()> {
739        Self::get_manager()
740            .disable_level(&login_id.to_login_id(), service, level, time)
741            .await
742    }
743
744    /// 校验封禁(默认服务 login、最低等级)
745    pub async fn check_disable(login_id: impl LoginId) -> SaTokenResult<()> {
746        Self::check_disable_level(login_id, crate::disable::DEFAULT_DISABLE_SERVICE, crate::disable::MIN_DISABLE_LEVEL).await
747    }
748
749    /// 校验指定服务的封禁
750    pub async fn check_disable_service(
751        login_id: impl LoginId,
752        service: &str,
753    ) -> SaTokenResult<()> {
754        Self::check_disable_level(login_id, service, crate::disable::MIN_DISABLE_LEVEL).await
755    }
756
757    /// 校验多个服务的封禁
758    pub async fn check_disable_services(
759        login_id: impl LoginId,
760        services: &[&str],
761    ) -> SaTokenResult<()> {
762        Self::get_manager()
763            .check_disable_services(
764                &login_id.to_login_id(),
765                services,
766                crate::disable::MIN_DISABLE_LEVEL,
767            )
768            .await
769    }
770
771    /// 校验封禁等级
772    pub async fn check_disable_level(
773        login_id: impl LoginId,
774        service: &str,
775        level: i32,
776    ) -> SaTokenResult<()> {
777        Self::get_manager()
778            .check_disable_level(&login_id.to_login_id(), service, level)
779            .await
780    }
781
782    /// 解封
783    pub async fn untie_disable(login_id: impl LoginId, service: &str) -> SaTokenResult<()> {
784        Self::get_manager()
785            .untie_disable(&login_id.to_login_id(), service)
786            .await
787    }
788}
789
790// ==================== 二级认证(safe) ====================
791
792impl StpUtil {
793    /// 为当前 token 开启二级认证
794    pub async fn open_safe(service: &str, safe_time: i64) -> SaTokenResult<()> {
795        let token = Self::get_token_value()?;
796        Self::get_manager().open_safe(&token, service, safe_time).await
797    }
798
799    /// 当前 token 是否已通过二级认证
800    pub async fn is_safe(service: &str) -> SaTokenResult<bool> {
801        let token = Self::get_token_value()?;
802        Self::get_manager().is_safe(&token, service).await
803    }
804
805    /// 校验当前 token 的二级认证
806    pub async fn check_safe(service: &str) -> SaTokenResult<()> {
807        Self::check_login_current()?;
808        let token = Self::get_token_value()?;
809        Self::get_manager().check_safe(&token, service).await
810    }
811
812    /// 关闭当前 token 的二级认证
813    pub async fn close_safe(service: &str) -> SaTokenResult<()> {
814        let token = Self::get_token_value()?;
815        Self::get_manager().close_safe(&token, service).await
816    }
817}
818
819// ==================== 身份临时切换 ====================
820
821impl StpUtil {
822    /// 临时切换为指定 login_id(写入请求上下文)
823    pub fn switch_to(login_id: impl LoginId) {
824        let mut ctx = SaTokenContext::get_current().unwrap_or_default();
825        ctx.switch_login_id = Some(login_id.to_login_id());
826        SaTokenContext::set_current(ctx);
827    }
828
829    /// 结束临时身份切换
830    pub fn end_switch() {
831        if let Some(mut ctx) = SaTokenContext::get_current() {
832            ctx.switch_login_id = None;
833            SaTokenContext::set_current(ctx);
834        }
835    }
836
837    /// 是否处于临时身份切换中
838    pub fn is_switch() -> bool {
839        SaTokenContext::get_current()
840            .and_then(|c| c.switch_login_id)
841            .is_some()
842    }
843
844    /// 获取临时切换的 login_id
845    pub fn get_switch_login_id() -> Option<String> {
846        SaTokenContext::get_current().and_then(|c| c.switch_login_id)
847    }
848}
849
850// ==================== 扩展工具方法 ====================
851
852impl StpUtil {
853    /// 批量踢人下线
854    pub async fn kick_out_batch<T: LoginId>(
855        login_ids: &[T],
856    ) -> SaTokenResult<Vec<Result<(), SaTokenError>>> {
857        let manager = Self::get_manager();
858        let mut results = Vec::new();
859        for login_id in login_ids {
860            results.push(manager.kick_out(&login_id.to_login_id()).await);
861        }
862        Ok(results)
863    }
864
865    /// 获取 token 剩余有效时间(秒)
866    pub async fn get_token_timeout(token: &TokenValue) -> SaTokenResult<Option<i64>> {
867        let manager = Self::get_manager();
868        let token_info = manager.get_token_info(token).await?;
869
870        if let Some(expire_time) = token_info.expire_time {
871            let now = chrono::Utc::now();
872            let duration = expire_time.signed_duration_since(now);
873            Ok(Some(duration.num_seconds()))
874        } else {
875            Ok(None) // 永久有效
876        }
877    }
878
879    /// 续期 token(重置过期时间)
880    pub async fn renew_timeout(
881        token: &TokenValue,
882        timeout_seconds: i64,
883    ) -> SaTokenResult<()> {
884        let manager = Self::get_manager();
885        let mut token_info = manager.get_token_info(token).await?;
886
887        // 设置新的过期时间
888        let new_expire_time = chrono::Utc::now() + chrono::Duration::seconds(timeout_seconds);
889        token_info.expire_time = Some(new_expire_time);
890
891        // 保存更新后的 token 信息
892        let key = manager.config.make_key("token:", token.as_str());
893        let value = serde_json::to_string(&token_info)
894            .map_err(SaTokenError::SerializationError)?;
895
896        let timeout = std::time::Duration::from_secs(timeout_seconds as u64);
897        manager.storage.set(&key, &value, Some(timeout)).await
898            .map_err(|e| SaTokenError::StorageError(e.to_string()))?;
899
900        Ok(())
901    }
902
903    // ==================== 额外数据操作 | Extra Data Operations ====================
904
905    /// 设置 Token 的额外数据 | Set extra data for token
906    ///
907    /// # 参数 | Arguments
908    /// * `token` - Token值 | Token value
909    /// * `extra_data` - 额外数据 | Extra data
910    pub async fn set_extra_data(
911        token: &TokenValue,
912        extra_data: serde_json::Value,
913    ) -> SaTokenResult<()> {
914        let manager = Self::get_manager();
915        let mut token_info = manager.get_token_info(token).await?;
916        token_info.extra_data = Some(extra_data);
917
918        let key = manager.config.make_key("token:", token.as_str());
919        let value = serde_json::to_string(&token_info)
920            .map_err(SaTokenError::SerializationError)?;
921
922        manager.storage.set(&key, &value, manager.config.timeout_duration()).await
923            .map_err(|e| SaTokenError::StorageError(e.to_string()))?;
924
925        Ok(())
926    }
927
928    /// 获取 Token 的额外数据 | Get extra data from token
929    ///
930    /// # 参数 | Arguments
931    /// * `token` - Token值 | Token value
932    pub async fn get_extra_data(token: &TokenValue) -> SaTokenResult<Option<serde_json::Value>> {
933        let manager = Self::get_manager();
934        let token_info = manager.get_token_info(token).await?;
935        Ok(token_info.extra_data)
936    }
937
938    // ==================== 终端信息 ====================
939
940    pub async fn get_terminal_list(
941        login_id: &str,
942        device_type: Option<&str>,
943    ) -> SaTokenResult<Vec<crate::session::SaTerminalInfo>> {
944        Self::get_manager()
945            .get_terminal_list("default", login_id, device_type)
946            .await
947    }
948
949    pub async fn get_token_value_list_by_login_id(
950        login_id: &str,
951        device_type: Option<&str>,
952    ) -> SaTokenResult<Vec<String>> {
953        Self::get_manager()
954            .get_token_value_list_by_login_id("default", login_id, device_type)
955            .await
956    }
957
958    pub async fn get_terminal_info_by_token(
959        token: &TokenValue,
960    ) -> SaTokenResult<Option<crate::session::SaTerminalInfo>> {
961        Self::get_manager()
962            .get_terminal_info_by_token(token)
963            .await
964    }
965
966    // ==================== 多账号体系 ====================
967
968    pub fn stp_logic(login_type: &str) -> Arc<crate::stp_logic::SaLogic> {
969        crate::stp_logic::get_or_create_stp_logic(login_type, Self::get_manager().clone())
970    }
971
972    pub fn put_stp_logic(logic: Arc<crate::stp_logic::SaLogic>) {
973        crate::stp_logic::put_stp_logic(logic);
974    }
975
976    pub fn remove_stp_logic(login_type: &str) {
977        crate::stp_logic::remove_stp_logic(login_type);
978    }
979
980    // ==================== 链式调用 | Chain Call ====================
981
982    /// 创建 Token 构建器,用于链式调用 | Create token builder for chain calls
983    ///
984    /// # 示例 | Example
985    /// ```rust,ignore
986    /// use serde_json::json;
987    ///
988    /// // 链式调用示例
989    /// let token = StpUtil::builder("user_123")
990    ///     .extra_data(json!({"ip": "192.168.1.1"}))
991    ///     .device("pc")
992    ///     .login_type("admin")
993    ///     .login()
994    ///     .await?;
995    /// ```
996    pub fn builder(login_id: impl LoginId) -> TokenBuilder {
997        TokenBuilder::new(login_id.to_login_id())
998    }
999}
1000
1001/// Token 构建器 - 支持链式调用 | Token Builder - Supports chain calls
1002pub struct TokenBuilder {
1003    login_id: String,
1004    extra_data: Option<serde_json::Value>,
1005    device: Option<String>,
1006    login_type: Option<String>,
1007}
1008
1009impl TokenBuilder {
1010    /// 创建新的 Token 构建器 | Create new token builder
1011    pub fn new(login_id: String) -> Self {
1012        Self {
1013            login_id,
1014            extra_data: None,
1015            device: None,
1016            login_type: None,
1017        }
1018    }
1019
1020    /// 设置额外数据 | Set extra data
1021    pub fn extra_data(mut self, data: serde_json::Value) -> Self {
1022        self.extra_data = Some(data);
1023        self
1024    }
1025
1026    /// 设置设备信息 | Set device info
1027    pub fn device(mut self, device: impl Into<String>) -> Self {
1028        self.device = Some(device.into());
1029        self
1030    }
1031
1032    /// 设置登录类型 | Set login type
1033    pub fn login_type(mut self, login_type: impl Into<String>) -> Self {
1034        self.login_type = Some(login_type.into());
1035        self
1036    }
1037
1038    /// 执行登录操作 | Execute login
1039    ///
1040    /// 如果不提供 login_id 参数,则使用构建器中的 login_id
1041    pub async fn login<T: LoginId>(self, login_id: Option<T>) -> SaTokenResult<TokenValue> {
1042        let manager = StpUtil::get_manager();
1043
1044        // 登录获取 token,使用传入的 login_id 或构建器中的 login_id
1045        let final_login_id = match login_id {
1046            Some(id) => id.to_login_id(),
1047            None => self.login_id,
1048        };
1049        let token = manager.login(final_login_id).await?;
1050
1051        // 获取 token 信息并修改
1052        let mut token_info = manager.get_token_info(&token).await?;
1053
1054        // 设置额外属性
1055        if let Some(data) = self.extra_data {
1056            token_info.extra_data = Some(data);
1057        }
1058
1059        if let Some(device) = self.device {
1060            token_info.device = Some(device);
1061        }
1062
1063        if let Some(login_type) = self.login_type {
1064            token_info.login_type = login_type;
1065        }
1066
1067        // 保存更新后的 token 信息
1068        let key = manager.config.make_key("token:", token.as_str());
1069        let value = serde_json::to_string(&token_info)
1070            .map_err(SaTokenError::SerializationError)?;
1071
1072        manager.storage.set(&key, &value, manager.config.timeout_duration()).await
1073            .map_err(|e| SaTokenError::StorageError(e.to_string()))?;
1074
1075        Ok(token)
1076    }
1077}
1078
1079#[cfg(test)]
1080mod tests {
1081    use super::*;
1082
1083    #[test]
1084    fn test_token_format_validation() {
1085        assert!(StpUtil::is_valid_token_format("1234567890abcdef"));
1086        assert!(!StpUtil::is_valid_token_format(""));
1087        assert!(!StpUtil::is_valid_token_format("short"));
1088    }
1089
1090    #[test]
1091    fn test_create_token() {
1092        let token = StpUtil::create_token("test-token-123");
1093        assert_eq!(token.as_str(), "test-token-123");
1094    }
1095}