1use std::borrow::Cow;
14use std::sync::Arc;
15use std::sync::OnceLock;
16
17use crate::context::SaTokenContext;
18use crate::event::{SaTokenEventBus, SaTokenListener};
19use crate::keys::LOGIN_TYPE_DEFAULT;
20use crate::session::SaSession;
21use crate::token::{TokenInfo, TokenValue};
22use crate::{SaTokenError, SaTokenManager, SaTokenResult};
23
24static GLOBAL_MANAGER: OnceLock<Arc<SaTokenManager>> = OnceLock::new();
26
27pub trait LoginId {
30 fn as_login_id(&self) -> Cow<'_, str>;
33
34 fn to_login_id(&self) -> String {
37 self.as_login_id().into_owned()
38 }
39}
40
41impl LoginId for str {
42 fn as_login_id(&self) -> Cow<'_, str> {
43 Cow::Borrowed(self)
44 }
45}
46
47impl LoginId for String {
48 fn as_login_id(&self) -> Cow<'_, str> {
49 Cow::Borrowed(self.as_str())
50 }
51}
52
53impl LoginId for &String {
54 fn as_login_id(&self) -> Cow<'_, str> {
55 Cow::Borrowed(self.as_str())
56 }
57}
58
59impl LoginId for &str {
60 fn as_login_id(&self) -> Cow<'_, str> {
61 Cow::Borrowed(*self)
62 }
63}
64
65macro_rules! impl_login_id_display {
66 ($($t:ty),*) => {$(
67 impl LoginId for $t {
68 fn as_login_id(&self) -> Cow<'_, str> {
69 Cow::Owned(self.to_string())
70 }
71 }
72 )*};
73}
74impl_login_id_display!(i32, i64, u32, u64, i16, u16, isize, usize);
75
76pub struct StpUtil;
79
80impl StpUtil {
81 pub fn try_init_manager(manager: SaTokenManager) -> SaTokenResult<()> {
89 GLOBAL_MANAGER
90 .set(Arc::new(manager))
91 .map_err(|_| SaTokenError::AlreadyInitialized)
92 }
93
94 #[deprecated(note = "use try_init_manager() which returns Result instead of panicking")]
105 #[allow(clippy::panic)]
106 pub fn init_manager(manager: SaTokenManager) {
107 Self::try_init_manager(manager).unwrap_or_else(|e| {
108 panic!("{e}");
109 });
110 }
111
112 pub fn try_get_manager() -> SaTokenResult<&'static Arc<SaTokenManager>> {
115 GLOBAL_MANAGER.get().ok_or(SaTokenError::NotInitialized)
116 }
117
118 #[track_caller]
121 #[allow(dead_code, clippy::panic)]
122 pub(crate) fn get_manager() -> &'static Arc<SaTokenManager> {
123 Self::try_get_manager().unwrap_or_else(|e| {
124 panic!("{e}. Call StpUtil::try_init_manager() first.");
125 })
126 }
127
128 pub(crate) fn try_get_config() -> Option<&'static crate::config::SaTokenConfig> {
132 GLOBAL_MANAGER.get().map(|m| m.config.as_ref())
133 }
134
135 #[inline]
145 fn resolve_login_type() -> Cow<'static, str> {
146 match SaTokenContext::current_login_type() {
147 Some(login_type) => Cow::Owned(login_type),
148 None => Cow::Borrowed(LOGIN_TYPE_DEFAULT),
149 }
150 }
151
152 pub fn event_bus() -> Option<&'static SaTokenEventBus> {
174 GLOBAL_MANAGER.get().map(|m| &m.event_bus)
175 }
176
177 pub fn register_listener(listener: Arc<dyn SaTokenListener>) {
185 if let Some(bus) = Self::event_bus() {
186 bus.register(listener);
187 }
188 }
189
190 pub async fn login(login_id: impl LoginId) -> SaTokenResult<TokenValue> {
204 Self::try_get_manager()?.login(login_id.to_login_id()).await
205 }
206
207 pub async fn login_with_type(
209 login_id: impl LoginId,
210 login_type: impl Into<String>,
211 ) -> SaTokenResult<TokenValue> {
212 Self::try_get_manager()?
213 .login_with_options(
214 login_id.to_login_id(),
215 Some(login_type.into()),
216 None,
217 None,
218 None,
219 None,
220 )
221 .await
222 }
223
224 pub async fn login_with_extra(
230 login_id: impl LoginId,
231 extra_data: serde_json::Value,
232 ) -> SaTokenResult<TokenValue> {
233 Self::try_get_manager()?
234 .login_with_options(
235 login_id.to_login_id(),
236 None, None, Some(extra_data),
239 None, None, )
242 .await
243 }
244
245 pub async fn login_with_manager(
247 manager: &SaTokenManager,
248 login_id: impl Into<String>,
249 ) -> SaTokenResult<TokenValue> {
250 manager.login(login_id).await
251 }
252
253 pub async fn logout(token: &TokenValue) -> SaTokenResult<()> {
255 tracing::debug!("开始执行 logout,token: {}", token);
256 let result = Self::try_get_manager()?.logout(token).await;
257 match &result {
258 Ok(_) => tracing::debug!("logout 执行成功,token: {}", token),
259 Err(e) => tracing::debug!("logout 执行失败,token: {}, 错误: {}", token, e),
260 }
261 result
262 }
263
264 pub async fn logout_with_manager(
266 manager: &SaTokenManager,
267 token: &TokenValue,
268 ) -> SaTokenResult<()> {
269 manager.logout(token).await
270 }
271
272 pub fn write_token_cookie<R: sa_token_adapter::context::SaResponse>(
275 res: &mut R,
276 token: &TokenValue,
277 ) -> SaTokenResult<()> {
278 let manager = Self::try_get_manager()?;
279 crate::token_io::write_token_cookie(res, token, &manager.config);
280 Ok(())
281 }
282
283 pub fn delete_token_cookie<R: sa_token_adapter::context::SaResponse>(
286 res: &mut R,
287 ) -> SaTokenResult<()> {
288 let manager = Self::try_get_manager()?;
289 crate::token_io::delete_token_cookie(res, &manager.config);
290 Ok(())
291 }
292
293 pub async fn update_active_timeout(token: &TokenValue, seconds: i64) -> SaTokenResult<()> {
296 Self::try_get_manager()?
297 .update_active_timeout(token, seconds)
298 .await
299 }
300
301 pub async fn kick_out(login_id: impl LoginId) -> SaTokenResult<()> {
304 let login_type = Self::resolve_login_type();
305 Self::kick_out_with_type(login_type.as_ref(), login_id).await
306 }
307
308 pub async fn kick_out_with_type(login_type: &str, login_id: impl LoginId) -> SaTokenResult<()> {
310 Self::try_get_manager()?
311 .kick_out(login_type, &login_id.to_login_id())
312 .await
313 }
314
315 pub async fn kick_out_with_manager(
317 manager: &SaTokenManager,
318 login_type: &str,
319 login_id: impl LoginId,
320 ) -> SaTokenResult<()> {
321 manager.kick_out(login_type, &login_id.to_login_id()).await
322 }
323
324 pub async fn logout_by_login_id(login_id: impl LoginId) -> SaTokenResult<()> {
327 let login_type = Self::resolve_login_type();
328 Self::logout_by_login_id_with_type(login_type.as_ref(), login_id).await
329 }
330
331 pub async fn logout_by_login_id_with_type(
333 login_type: &str,
334 login_id: impl LoginId,
335 ) -> SaTokenResult<()> {
336 Self::try_get_manager()?
337 .logout_by_login_id(login_type, &login_id.to_login_id())
338 .await
339 }
340
341 pub async fn logout_by_token(token: &TokenValue) -> SaTokenResult<()> {
343 Self::logout(token).await
344 }
345
346 pub fn get_token_value() -> SaTokenResult<TokenValue> {
356 let ctx = SaTokenContext::try_current().ok_or(SaTokenError::NotLogin)?;
357 ctx.token().ok_or(SaTokenError::NotLogin)
358 }
359
360 pub async fn logout_current() -> SaTokenResult<()> {
368 let token = Self::get_token_value()?;
369 tracing::debug!("成功获取 token: {}", token);
370
371 let result = Self::logout(&token).await;
372 match &result {
373 Ok(_) => tracing::debug!("logout_current 执行成功,token: {}", token),
374 Err(e) => tracing::debug!("logout_current 执行失败,token: {}, 错误: {}", token, e),
375 }
376 result
377 }
378
379 pub fn is_login_current() -> bool {
385 Self::get_token_value().is_ok()
386 }
387
388 pub fn check_login_current() -> SaTokenResult<()> {
391 Self::get_token_value()?;
392 Ok(())
393 }
394
395 pub async fn check_login_current_async() -> SaTokenResult<()> {
398 let token = Self::get_token_value()?;
399 if !Self::try_get_manager()?.is_valid(&token).await {
400 return Err(SaTokenError::NotLogin);
401 }
402 Ok(())
403 }
404
405 pub async fn is_login_current_async() -> bool {
408 Self::check_login_current_async().await.is_ok()
409 }
410
411 pub async fn get_login_id_as_string() -> SaTokenResult<String> {
419 if let Some(ctx) = SaTokenContext::get_current() {
420 if let Some(switch_id) = ctx.switch_login_id() {
421 return Ok(switch_id);
422 }
423 }
424 let token = Self::get_token_value()?;
425 Self::get_login_id(&token).await
426 }
427
428 pub async fn get_login_id_as_long() -> SaTokenResult<i64> {
436 let login_id_str = Self::get_login_id_as_string().await?;
437 login_id_str
438 .parse::<i64>()
439 .map_err(|_| SaTokenError::LoginIdNotNumber)
440 }
441
442 pub fn get_token_info_current() -> SaTokenResult<Arc<TokenInfo>> {
451 let ctx = SaTokenContext::try_current().ok_or(SaTokenError::NotLogin)?;
452 ctx.token_info().ok_or(SaTokenError::NotLogin)
453 }
454
455 pub async fn is_login(token: &TokenValue) -> bool {
459 let Ok(manager) = Self::try_get_manager() else {
460 return false;
461 };
462 manager.is_valid(token).await
463 }
464
465 pub async fn is_login_by_login_id(login_id: impl LoginId) -> bool {
473 match Self::get_token_by_login_id(login_id).await {
474 Ok(token) => Self::is_login(&token).await,
475 Err(_) => false,
476 }
477 }
478
479 pub async fn is_login_with_manager(manager: &SaTokenManager, token: &TokenValue) -> bool {
481 manager.is_valid(token).await
482 }
483
484 pub async fn check_login(token: &TokenValue) -> SaTokenResult<()> {
486 if !Self::is_login(token).await {
487 return Err(SaTokenError::NotLogin);
488 }
489 Ok(())
490 }
491
492 pub async fn get_token_info(token: &TokenValue) -> SaTokenResult<TokenInfo> {
494 Self::try_get_manager()?.get_token_info(token).await
495 }
496
497 pub async fn get_login_id(token: &TokenValue) -> SaTokenResult<String> {
499 let token_info = Self::try_get_manager()?.get_token_info(token).await?;
500 Ok(token_info.login_id.to_string())
501 }
502
503 pub async fn get_login_id_or_default(token: &TokenValue, default: impl Into<String>) -> String {
505 Self::get_login_id(token)
506 .await
507 .unwrap_or_else(|_| default.into())
508 }
509
510 pub async fn get_token_by_login_id(login_id: impl LoginId) -> SaTokenResult<TokenValue> {
518 let login_type = Self::resolve_login_type();
519 Self::get_token_by_login_id_with_type(login_type.as_ref(), login_id).await
520 }
521
522 pub async fn get_token_by_login_id_with_type(
526 login_type: &str,
527 login_id: impl LoginId,
528 ) -> SaTokenResult<TokenValue> {
529 Self::try_get_manager()?
530 .get_token_by_login_id(login_type, &login_id.to_login_id())
531 .await
532 }
533
534 pub async fn get_all_tokens_by_login_id(
536 login_id: impl LoginId,
537 ) -> SaTokenResult<Vec<TokenValue>> {
538 let login_type = Self::resolve_login_type();
539 Self::get_all_tokens_by_login_id_with_type(login_type.as_ref(), login_id).await
540 }
541
542 pub async fn get_all_tokens_by_login_id_with_type(
546 login_type: &str,
547 login_id: impl LoginId,
548 ) -> SaTokenResult<Vec<TokenValue>> {
549 Self::try_get_manager()?
550 .get_all_tokens_by_login_id(login_type, &login_id.to_login_id())
551 .await
552 }
553
554 pub async fn get_session_with_type(
558 login_type: &str,
559 login_id: impl LoginId,
560 ) -> SaTokenResult<SaSession> {
561 Self::try_get_manager()?
562 .get_session_with_type(login_type, &login_id.to_login_id())
563 .await
564 }
565
566 pub async fn delete_session_with_type(
568 login_type: &str,
569 login_id: impl LoginId,
570 ) -> SaTokenResult<()> {
571 Self::try_get_manager()?
572 .delete_session_with_type(login_type, &login_id.to_login_id())
573 .await
574 }
575
576 pub async fn get_session(login_id: impl LoginId) -> SaTokenResult<SaSession> {
579 let login_type = Self::resolve_login_type();
580 Self::get_session_with_type(login_type.as_ref(), login_id).await
581 }
582
583 pub async fn save_session(session: &SaSession) -> SaTokenResult<()> {
585 Self::try_get_manager()?.save_session(session).await
586 }
587
588 pub async fn delete_session(login_id: impl LoginId) -> SaTokenResult<()> {
591 let login_type = Self::resolve_login_type();
592 Self::delete_session_with_type(login_type.as_ref(), login_id).await
593 }
594
595 pub async fn set_session_value<T: serde::Serialize>(
598 login_id: impl LoginId,
599 key: &str,
600 value: T,
601 ) -> SaTokenResult<()> {
602 let login_type = Self::resolve_login_type();
603 let manager = Self::try_get_manager()?;
604 let login_id_str = login_id.to_login_id();
605 let mut session = manager
606 .get_session_with_type(login_type.as_ref(), &login_id_str)
607 .await?;
608 session.set(key, value)?;
609 manager.save_session(&session).await
610 }
611
612 pub async fn get_session_value<T: serde::de::DeserializeOwned>(
615 login_id: impl LoginId,
616 key: &str,
617 ) -> SaTokenResult<Option<T>> {
618 let login_type = Self::resolve_login_type();
619 let session = Self::get_session_with_type(login_type.as_ref(), login_id).await?;
620 Ok(session.get::<T>(key))
621 }
622
623 pub fn create_token(token_value: impl Into<String>) -> TokenValue {
627 TokenValue::new(token_value.into())
628 }
629
630 pub fn is_valid_token_format(token: &str) -> bool {
632 !token.is_empty() && token.len() >= 16
633 }
634}
635
636impl std::fmt::Debug for StpUtil {
637 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
638 f.write_str("StpUtil { .. }")
639 }
640}
641
642impl StpUtil {
645 pub async fn set_permissions_with_type(
649 login_type: &str,
650 login_id: impl LoginId,
651 permissions: Vec<String>,
652 ) -> SaTokenResult<()> {
653 Self::try_get_manager()?
654 .set_permissions_with_type(login_type, &login_id.to_login_id(), permissions)
655 .await
656 }
657
658 pub async fn set_permissions(
660 login_id: impl LoginId,
661 permissions: Vec<String>,
662 ) -> SaTokenResult<()> {
663 let login_type = Self::resolve_login_type();
664 Self::set_permissions_with_type(&login_type, login_id, permissions).await
665 }
666
667 pub async fn add_permission_with_type(
669 login_type: &str,
670 login_id: impl LoginId,
671 permission: impl Into<String>,
672 ) -> SaTokenResult<()> {
673 Self::try_get_manager()?
674 .add_permission_with_type(login_type, &login_id.to_login_id(), permission.into())
675 .await
676 }
677
678 pub async fn add_permission(
680 login_id: impl LoginId,
681 permission: impl Into<String>,
682 ) -> SaTokenResult<()> {
683 let login_type = Self::resolve_login_type();
684 Self::add_permission_with_type(&login_type, login_id, permission).await
685 }
686
687 pub async fn remove_permission_with_type(
689 login_type: &str,
690 login_id: impl LoginId,
691 permission: &str,
692 ) -> SaTokenResult<()> {
693 Self::try_get_manager()?
694 .remove_permission_with_type(login_type, &login_id.to_login_id(), permission)
695 .await
696 }
697
698 pub async fn remove_permission(login_id: impl LoginId, permission: &str) -> SaTokenResult<()> {
700 let login_type = Self::resolve_login_type();
701 Self::remove_permission_with_type(&login_type, login_id, permission).await
702 }
703
704 pub async fn clear_permissions_with_type(
706 login_type: &str,
707 login_id: impl LoginId,
708 ) -> SaTokenResult<()> {
709 Self::try_get_manager()?
710 .clear_permissions_with_type(login_type, &login_id.to_login_id())
711 .await
712 }
713
714 pub async fn clear_permissions(login_id: impl LoginId) -> SaTokenResult<()> {
716 let login_type = Self::resolve_login_type();
717 Self::clear_permissions_with_type(&login_type, login_id).await
718 }
719
720 pub async fn try_get_permissions_with_type(
725 login_type: &str,
726 login_id: impl LoginId,
727 ) -> SaTokenResult<Vec<String>> {
728 Self::try_get_manager()?
729 .get_permissions_with_type(login_type, &login_id.to_login_id())
730 .await
731 }
732
733 pub async fn try_get_permissions(login_id: impl LoginId) -> SaTokenResult<Vec<String>> {
736 let login_type = Self::resolve_login_type();
737 Self::try_get_permissions_with_type(&login_type, login_id).await
738 }
739
740 pub async fn get_permissions(login_id: impl LoginId) -> Vec<String> {
743 let login_id = login_id.to_login_id();
744 match Self::try_get_permissions(&login_id).await {
745 Ok(list) => list,
746 Err(e) => {
747 tracing::warn!(
748 login_id = %login_id,
749 error = %e,
750 "failed to load permissions, treating as empty"
751 );
752 Vec::new()
753 }
754 }
755 }
756
757 pub async fn has_permission_with_type(
761 login_type: &str,
762 login_id: impl LoginId,
763 permission: &str,
764 ) -> bool {
765 let Ok(manager) = Self::try_get_manager() else {
766 return false;
767 };
768 manager
769 .authz_service()
770 .has_permission(login_type, &login_id.to_login_id(), permission)
771 .await
772 .unwrap_or(false)
773 }
774
775 pub async fn has_permission(login_id: impl LoginId, permission: &str) -> bool {
777 let login_type = Self::resolve_login_type();
778 Self::has_permission_with_type(&login_type, login_id, permission).await
779 }
780
781 pub async fn has_all_permissions_with_type(
783 login_type: &str,
784 login_id: impl LoginId,
785 permissions: &[&str],
786 ) -> bool {
787 let Ok(manager) = Self::try_get_manager() else {
788 return false;
789 };
790 manager
791 .authz_service()
792 .has_all_permissions(login_type, &login_id.to_login_id(), permissions)
793 .await
794 .unwrap_or(false)
795 }
796
797 pub async fn has_all_permissions(login_id: impl LoginId, permissions: &[&str]) -> bool {
799 let login_type = Self::resolve_login_type();
800 Self::has_all_permissions_with_type(&login_type, login_id, permissions).await
801 }
802
803 pub async fn has_permissions_and(login_id: impl LoginId, permissions: &[&str]) -> bool {
805 Self::has_all_permissions(login_id, permissions).await
806 }
807
808 pub async fn has_any_permission_with_type(
810 login_type: &str,
811 login_id: impl LoginId,
812 permissions: &[&str],
813 ) -> bool {
814 let Ok(manager) = Self::try_get_manager() else {
815 return false;
816 };
817 manager
818 .authz_service()
819 .has_any_permission(login_type, &login_id.to_login_id(), permissions)
820 .await
821 .unwrap_or(false)
822 }
823
824 pub async fn has_any_permission(login_id: impl LoginId, permissions: &[&str]) -> bool {
826 let login_type = Self::resolve_login_type();
827 Self::has_any_permission_with_type(&login_type, login_id, permissions).await
828 }
829
830 pub async fn has_permissions_or(login_id: impl LoginId, permissions: &[&str]) -> bool {
832 Self::has_any_permission(login_id, permissions).await
833 }
834
835 pub async fn check_permission_with_type(
838 login_type: &str,
839 login_id: impl LoginId,
840 permission: &str,
841 ) -> SaTokenResult<()> {
842 Self::try_get_manager()?
843 .authz_service()
844 .check_permission(login_type, &login_id.to_login_id(), permission)
845 .await
846 }
847
848 pub async fn check_permission(login_id: impl LoginId, permission: &str) -> SaTokenResult<()> {
850 let login_type = Self::resolve_login_type();
851 Self::check_permission_with_type(&login_type, login_id, permission).await
852 }
853
854 pub async fn check_all_permissions(
857 login_id: impl LoginId,
858 permissions: &[&str],
859 ) -> SaTokenResult<()> {
860 let login_type = Self::resolve_login_type();
861 Self::try_get_manager()?
862 .authz_service()
863 .check_all_permissions(&login_type, &login_id.to_login_id(), permissions)
864 .await
865 }
866
867 pub async fn check_any_permission(
870 login_id: impl LoginId,
871 permissions: &[&str],
872 ) -> SaTokenResult<()> {
873 let login_type = Self::resolve_login_type();
874 Self::try_get_manager()?
875 .authz_service()
876 .check_any_permission(&login_type, &login_id.to_login_id(), permissions)
877 .await
878 }
879}
880
881impl StpUtil {
884 pub async fn set_roles_with_type(
888 login_type: &str,
889 login_id: impl LoginId,
890 roles: Vec<String>,
891 ) -> SaTokenResult<()> {
892 Self::try_get_manager()?
893 .set_roles_with_type(login_type, &login_id.to_login_id(), roles)
894 .await
895 }
896
897 pub async fn set_roles(login_id: impl LoginId, roles: Vec<String>) -> SaTokenResult<()> {
899 let login_type = Self::resolve_login_type();
900 Self::set_roles_with_type(&login_type, login_id, roles).await
901 }
902
903 pub async fn add_role_with_type(
905 login_type: &str,
906 login_id: impl LoginId,
907 role: impl Into<String>,
908 ) -> SaTokenResult<()> {
909 Self::try_get_manager()?
910 .add_role_with_type(login_type, &login_id.to_login_id(), role.into())
911 .await
912 }
913
914 pub async fn add_role(login_id: impl LoginId, role: impl Into<String>) -> SaTokenResult<()> {
916 let login_type = Self::resolve_login_type();
917 Self::add_role_with_type(&login_type, login_id, role).await
918 }
919
920 pub async fn remove_role_with_type(
922 login_type: &str,
923 login_id: impl LoginId,
924 role: &str,
925 ) -> SaTokenResult<()> {
926 Self::try_get_manager()?
927 .remove_role_with_type(login_type, &login_id.to_login_id(), role)
928 .await
929 }
930
931 pub async fn remove_role(login_id: impl LoginId, role: &str) -> SaTokenResult<()> {
933 let login_type = Self::resolve_login_type();
934 Self::remove_role_with_type(&login_type, login_id, role).await
935 }
936
937 pub async fn clear_roles_with_type(
939 login_type: &str,
940 login_id: impl LoginId,
941 ) -> SaTokenResult<()> {
942 Self::try_get_manager()?
943 .clear_roles_with_type(login_type, &login_id.to_login_id())
944 .await
945 }
946
947 pub async fn clear_roles(login_id: impl LoginId) -> SaTokenResult<()> {
949 let login_type = Self::resolve_login_type();
950 Self::clear_roles_with_type(&login_type, login_id).await
951 }
952
953 pub async fn try_get_roles_with_type(
958 login_type: &str,
959 login_id: impl LoginId,
960 ) -> SaTokenResult<Vec<String>> {
961 Self::try_get_manager()?
962 .get_roles_with_type(login_type, &login_id.to_login_id())
963 .await
964 }
965
966 pub async fn try_get_roles(login_id: impl LoginId) -> SaTokenResult<Vec<String>> {
968 let login_type = Self::resolve_login_type();
969 Self::try_get_roles_with_type(&login_type, login_id).await
970 }
971
972 pub async fn get_roles(login_id: impl LoginId) -> Vec<String> {
974 let login_id = login_id.to_login_id();
975 match Self::try_get_roles(&login_id).await {
976 Ok(list) => list,
977 Err(e) => {
978 tracing::warn!(
979 login_id = %login_id,
980 error = %e,
981 "failed to load roles, treating as empty"
982 );
983 Vec::new()
984 }
985 }
986 }
987
988 pub async fn has_role_with_type(login_type: &str, login_id: impl LoginId, role: &str) -> bool {
992 let Ok(manager) = Self::try_get_manager() else {
993 return false;
994 };
995 manager
996 .authz_service()
997 .has_role(login_type, &login_id.to_login_id(), role)
998 .await
999 .unwrap_or(false)
1000 }
1001
1002 pub async fn has_role(login_id: impl LoginId, role: &str) -> bool {
1004 let login_type = Self::resolve_login_type();
1005 Self::has_role_with_type(&login_type, login_id, role).await
1006 }
1007
1008 pub async fn has_all_roles_with_type(
1010 login_type: &str,
1011 login_id: impl LoginId,
1012 roles: &[&str],
1013 ) -> bool {
1014 let Ok(manager) = Self::try_get_manager() else {
1015 return false;
1016 };
1017 manager
1018 .authz_service()
1019 .has_all_roles(login_type, &login_id.to_login_id(), roles)
1020 .await
1021 .unwrap_or(false)
1022 }
1023
1024 pub async fn has_all_roles(login_id: impl LoginId, roles: &[&str]) -> bool {
1026 let login_type = Self::resolve_login_type();
1027 Self::has_all_roles_with_type(&login_type, login_id, roles).await
1028 }
1029
1030 pub async fn has_roles_and(login_id: impl LoginId, roles: &[&str]) -> bool {
1032 Self::has_all_roles(login_id, roles).await
1033 }
1034
1035 pub async fn has_any_role_with_type(
1037 login_type: &str,
1038 login_id: impl LoginId,
1039 roles: &[&str],
1040 ) -> bool {
1041 let Ok(manager) = Self::try_get_manager() else {
1042 return false;
1043 };
1044 manager
1045 .authz_service()
1046 .has_any_role(login_type, &login_id.to_login_id(), roles)
1047 .await
1048 .unwrap_or(false)
1049 }
1050
1051 pub async fn has_any_role(login_id: impl LoginId, roles: &[&str]) -> bool {
1053 let login_type = Self::resolve_login_type();
1054 Self::has_any_role_with_type(&login_type, login_id, roles).await
1055 }
1056
1057 pub async fn has_roles_or(login_id: impl LoginId, roles: &[&str]) -> bool {
1059 Self::has_any_role(login_id, roles).await
1060 }
1061
1062 pub async fn check_role_with_type(
1065 login_type: &str,
1066 login_id: impl LoginId,
1067 role: &str,
1068 ) -> SaTokenResult<()> {
1069 Self::try_get_manager()?
1070 .authz_service()
1071 .check_role(login_type, &login_id.to_login_id(), role)
1072 .await
1073 }
1074
1075 pub async fn check_role(login_id: impl LoginId, role: &str) -> SaTokenResult<()> {
1077 let login_type = Self::resolve_login_type();
1078 Self::check_role_with_type(&login_type, login_id, role).await
1079 }
1080
1081 pub async fn check_all_roles(login_id: impl LoginId, roles: &[&str]) -> SaTokenResult<()> {
1084 let login_type = Self::resolve_login_type();
1085 Self::try_get_manager()?
1086 .authz_service()
1087 .check_all_roles(&login_type, &login_id.to_login_id(), roles)
1088 .await
1089 }
1090
1091 pub async fn check_any_role(login_id: impl LoginId, roles: &[&str]) -> SaTokenResult<()> {
1094 let login_type = Self::resolve_login_type();
1095 Self::try_get_manager()?
1096 .authz_service()
1097 .check_any_role(&login_type, &login_id.to_login_id(), roles)
1098 .await
1099 }
1100}
1101
1102impl StpUtil {
1105 pub async fn disable(login_id: impl LoginId, time: i64) -> SaTokenResult<()> {
1108 let login_type = Self::resolve_login_type();
1109 Self::try_get_manager()?
1110 .disable_with_type(login_type.as_ref(), &login_id.to_login_id(), time)
1111 .await
1112 }
1113
1114 pub async fn disable_with_type(
1117 login_type: &str,
1118 login_id: impl LoginId,
1119 time: i64,
1120 ) -> SaTokenResult<()> {
1121 Self::try_get_manager()?
1122 .disable_with_type(login_type, &login_id.to_login_id(), time)
1123 .await
1124 }
1125
1126 pub async fn disable_level(
1129 login_id: impl LoginId,
1130 service: &str,
1131 level: i32,
1132 time: i64,
1133 ) -> SaTokenResult<()> {
1134 let login_type = Self::resolve_login_type();
1135 Self::try_get_manager()?
1136 .disable_level_with_type(
1137 login_type.as_ref(),
1138 &login_id.to_login_id(),
1139 service,
1140 level,
1141 time,
1142 )
1143 .await
1144 }
1145
1146 pub async fn check_disable(login_id: impl LoginId) -> SaTokenResult<()> {
1148 Self::check_disable_level(
1149 login_id,
1150 crate::disable::DEFAULT_DISABLE_SERVICE,
1151 crate::disable::MIN_DISABLE_LEVEL,
1152 )
1153 .await
1154 }
1155
1156 pub async fn check_disable_service(login_id: impl LoginId, service: &str) -> SaTokenResult<()> {
1158 Self::check_disable_level(login_id, service, crate::disable::MIN_DISABLE_LEVEL).await
1159 }
1160
1161 pub async fn check_disable_services(
1163 login_id: impl LoginId,
1164 services: &[&str],
1165 ) -> SaTokenResult<()> {
1166 let login_type = Self::resolve_login_type();
1167 Self::try_get_manager()?
1168 .check_disable_services_with_type(
1169 login_type.as_ref(),
1170 &login_id.to_login_id(),
1171 services,
1172 crate::disable::MIN_DISABLE_LEVEL,
1173 )
1174 .await
1175 }
1176
1177 pub async fn check_disable_level(
1179 login_id: impl LoginId,
1180 service: &str,
1181 level: i32,
1182 ) -> SaTokenResult<()> {
1183 let login_type = Self::resolve_login_type();
1184 Self::try_get_manager()?
1185 .check_disable_level_with_type(
1186 login_type.as_ref(),
1187 &login_id.to_login_id(),
1188 service,
1189 level,
1190 )
1191 .await
1192 }
1193
1194 pub async fn get_disable_level(login_id: impl LoginId, service: &str) -> SaTokenResult<i32> {
1197 let login_type = Self::resolve_login_type();
1198 Self::get_disable_level_with_type(login_type.as_ref(), login_id, service).await
1199 }
1200
1201 pub async fn get_disable_level_with_type(
1204 login_type: &str,
1205 login_id: impl LoginId,
1206 service: &str,
1207 ) -> SaTokenResult<i32> {
1208 Self::try_get_manager()?
1209 .get_disable_level_with_type(login_type, &login_id.to_login_id(), service)
1210 .await
1211 }
1212
1213 pub async fn untie_disable(login_id: impl LoginId, service: &str) -> SaTokenResult<()> {
1215 let login_type = Self::resolve_login_type();
1216 Self::try_get_manager()?
1217 .untie_disable_with_type(login_type.as_ref(), &login_id.to_login_id(), service)
1218 .await
1219 }
1220}
1221
1222impl StpUtil {
1225 pub async fn open_safe(service: &str, safe_time: i64) -> SaTokenResult<()> {
1227 let token = Self::get_token_value()?;
1228 Self::try_get_manager()?
1229 .open_safe(&token, service, safe_time)
1230 .await
1231 }
1232
1233 pub async fn is_safe(service: &str) -> SaTokenResult<bool> {
1235 let token = Self::get_token_value()?;
1236 Self::try_get_manager()?.is_safe(&token, service).await
1237 }
1238
1239 pub async fn check_safe(service: &str) -> SaTokenResult<()> {
1241 Self::check_login_current()?;
1242 let token = Self::get_token_value()?;
1243 Self::try_get_manager()?.check_safe(&token, service).await
1244 }
1245
1246 pub async fn close_safe(service: &str) -> SaTokenResult<()> {
1248 let token = Self::get_token_value()?;
1249 Self::try_get_manager()?.close_safe(&token, service).await
1250 }
1251}
1252
1253impl StpUtil {
1256 pub fn switch_to(login_id: impl LoginId) {
1260 let target = login_id.to_login_id();
1261 SaTokenContext::with_current_mut(|inner| {
1262 inner.switch_login_id = Some(target);
1263 });
1264 }
1265
1266 pub fn end_switch() {
1270 SaTokenContext::with_current_mut(|inner| {
1271 inner.switch_login_id = None;
1272 });
1273 }
1274
1275 pub fn is_switch() -> bool {
1279 SaTokenContext::get_current()
1280 .and_then(|c| c.switch_login_id())
1281 .is_some()
1282 }
1283
1284 pub fn get_switch_login_id() -> Option<String> {
1288 SaTokenContext::get_current().and_then(|c| c.switch_login_id())
1289 }
1290}
1291
1292impl StpUtil {
1295 pub async fn kick_out_batch<T: LoginId>(
1298 login_ids: &[T],
1299 ) -> SaTokenResult<Vec<Result<(), SaTokenError>>> {
1300 let manager = Self::try_get_manager()?;
1301 let login_type = Self::resolve_login_type();
1302 let mut results = Vec::new();
1303 for login_id in login_ids {
1304 results.push(
1305 manager
1306 .kick_out(login_type.as_ref(), &login_id.to_login_id())
1307 .await,
1308 );
1309 }
1310 Ok(results)
1311 }
1312
1313 pub async fn get_token_timeout(token: &TokenValue) -> SaTokenResult<Option<i64>> {
1315 let manager = Self::try_get_manager()?;
1316 let token_info = manager.get_token_info(token).await?;
1317
1318 if let Some(expire_time) = token_info.expire_time {
1319 let now = chrono::Utc::now();
1320 let duration = expire_time.signed_duration_since(now);
1321 Ok(Some(duration.num_seconds()))
1322 } else {
1323 Ok(None) }
1325 }
1326
1327 pub async fn renew_timeout(token: &TokenValue, timeout_seconds: i64) -> SaTokenResult<()> {
1331 Self::try_get_manager()?
1332 .renew_timeout(token, timeout_seconds)
1333 .await
1334 }
1335
1336 pub async fn set_extra_data(
1342 token: &TokenValue,
1343 extra_data: serde_json::Value,
1344 ) -> SaTokenResult<()> {
1345 Self::try_get_manager()?
1346 .update_extra_data(token, extra_data)
1347 .await
1348 }
1349
1350 pub async fn get_extra_data(token: &TokenValue) -> SaTokenResult<Option<serde_json::Value>> {
1355 let manager = Self::try_get_manager()?;
1356 let token_info = manager.get_token_info(token).await?;
1357 Ok(token_info.extra_data)
1358 }
1359
1360 pub async fn get_terminal_list(
1364 login_id: &str,
1365 device_type: Option<&str>,
1366 ) -> SaTokenResult<Vec<crate::session::SaTerminalInfo>> {
1367 let login_type = Self::resolve_login_type();
1368 Self::try_get_manager()?
1369 .get_terminal_list(login_type.as_ref(), login_id, device_type)
1370 .await
1371 }
1372
1373 pub async fn get_token_value_list_by_login_id(
1375 login_id: &str,
1376 device_type: Option<&str>,
1377 ) -> SaTokenResult<Vec<String>> {
1378 let login_type = Self::resolve_login_type();
1379 Self::try_get_manager()?
1380 .get_token_value_list_by_login_id(login_type.as_ref(), login_id, device_type)
1381 .await
1382 }
1383
1384 pub async fn get_terminal_info_by_token(
1386 token: &TokenValue,
1387 ) -> SaTokenResult<Option<crate::session::SaTerminalInfo>> {
1388 Self::try_get_manager()?
1389 .get_terminal_info_by_token(token)
1390 .await
1391 }
1392
1393 pub async fn check_current_terminal(expected: &str) -> SaTokenResult<()> {
1396 Self::check_login_current_async().await?;
1397 let token = Self::get_token_value()?;
1398 let term = Self::get_terminal_info_by_token(&token).await?;
1399 let actual = term.map(|t| t.device_type).unwrap_or_default();
1400 if actual != expected {
1401 return Err(SaTokenError::TerminalDenied {
1402 expected: expected.to_string(),
1403 actual,
1404 });
1405 }
1406 Ok(())
1407 }
1408
1409 pub fn stp_logic(login_type: &str) -> SaTokenResult<crate::stp_logic::SaLogic> {
1414 Ok(crate::stp_logic::SaLogic::new(
1415 login_type,
1416 Self::try_get_manager()?.as_ref().clone(),
1417 ))
1418 }
1419
1420 #[deprecated(note = "SaLogic is a cloneable facade; use SaLogic::new / StpUtil::stp_logic")]
1423 pub fn put_stp_logic(_logic: crate::stp_logic::SaLogic) {}
1424
1425 #[deprecated(note = "SaLogic is a cloneable facade; nothing to remove")]
1428 pub fn remove_stp_logic(_login_type: &str) {}
1429
1430 pub async fn get_token_session(token: &TokenValue) -> SaTokenResult<SaSession> {
1434 Self::try_get_manager()?.get_token_session(token).await
1435 }
1436
1437 pub async fn get_token_session_current() -> SaTokenResult<SaSession> {
1439 let token = Self::get_token_value()?;
1440 Self::get_token_session(&token).await
1441 }
1442
1443 pub async fn save_token_session(token: &TokenValue, session: &SaSession) -> SaTokenResult<()> {
1445 Self::try_get_manager()?
1446 .save_token_session(token, session)
1447 .await
1448 }
1449
1450 pub async fn delete_token_session(token: &TokenValue) -> SaTokenResult<()> {
1452 Self::try_get_manager()?.delete_token_session(token).await
1453 }
1454
1455 pub async fn kick_out_by_token(token: &TokenValue) -> SaTokenResult<()> {
1457 Self::try_get_manager()?.kick_out_by_token(token).await
1458 }
1459
1460 pub async fn with_grant_scope<F, T>(future: F) -> T
1465 where
1466 F: Future<Output = T>,
1467 {
1468 crate::context::GrantScope::run(crate::context::GrantScope::new(), future).await
1469 }
1470
1471 pub async fn check_permission_or_role(
1474 login_id: impl LoginId,
1475 permissions: &[&str],
1476 roles: &[&str],
1477 ) -> SaTokenResult<()> {
1478 let login_type = Self::resolve_login_type();
1479 let login_id = login_id.to_login_id();
1480 let authz = Self::try_get_manager()?.authz_service();
1481
1482 if !permissions.is_empty()
1483 && authz
1484 .has_any_permission(&login_type, &login_id, permissions)
1485 .await?
1486 {
1487 return Ok(());
1488 }
1489 if !roles.is_empty() && authz.has_any_role(&login_type, &login_id, roles).await? {
1490 return Ok(());
1491 }
1492
1493 Err(SaTokenError::PermissionDeniedDetail(format!(
1494 "none of permissions [{}] or roles [{}] matched",
1495 permissions.join(", "),
1496 roles.join(", ")
1497 )))
1498 }
1499
1500 pub fn builder(login_id: impl LoginId) -> TokenBuilder {
1517 TokenBuilder::new(login_id.to_login_id())
1518 }
1519
1520 pub fn request_sign() -> SaTokenResult<crate::sign::RequestSign> {
1525 let manager = Self::try_get_manager()?;
1526 let secret = manager
1527 .config
1528 .sign_secret_key
1529 .clone()
1530 .filter(|s| !s.is_empty())
1531 .ok_or_else(|| SaTokenError::ConfigError("sign_secret_key is not configured".into()))?;
1532 Ok(
1533 crate::sign::RequestSign::new(secret, manager.config.sign_window_secs)
1534 .with_dao(manager.dao().clone()),
1535 )
1536 }
1537
1538 pub async fn sign_params(
1541 params: std::collections::BTreeMap<String, String>,
1542 ) -> SaTokenResult<std::collections::BTreeMap<String, String>> {
1543 Self::request_sign()?.create_signed(params)
1544 }
1545
1546 pub async fn check_sign(
1549 params: &std::collections::BTreeMap<String, String>,
1550 ) -> SaTokenResult<()> {
1551 let sign = params
1552 .get("sign")
1553 .cloned()
1554 .ok_or(SaTokenError::SignInvalid)?;
1555 Self::request_sign()?.verify_params(params, &sign).await
1556 }
1557
1558 pub async fn get_same_token() -> SaTokenResult<String> {
1563 crate::same_token::get_token().await
1564 }
1565
1566 pub async fn refresh_same_token() -> SaTokenResult<String> {
1569 crate::same_token::refresh_token().await
1570 }
1571
1572 pub async fn check_same_token(token: &str) -> SaTokenResult<()> {
1575 crate::same_token::check_token(token).await
1576 }
1577
1578 pub async fn create_temp_token(
1583 value: impl Into<String>,
1584 timeout_secs: i64,
1585 ) -> SaTokenResult<String> {
1586 crate::temp_token::create_default(value, timeout_secs).await
1587 }
1588
1589 pub async fn parse_temp_token(
1592 token: &str,
1593 ) -> SaTokenResult<crate::temp_token::TempTokenRecord> {
1594 crate::temp_token::parse_default(token).await
1595 }
1596
1597 pub async fn delete_temp_token(token: &str) -> SaTokenResult<()> {
1600 crate::temp_token::delete_default(token).await
1601 }
1602}
1603
1604pub struct TokenBuilder {
1606 login_id: String,
1607 extra_data: Option<serde_json::Value>,
1608 device: Option<String>,
1609 login_type: Option<String>,
1610 nonce: Option<String>,
1611 expire_time: Option<chrono::DateTime<chrono::Utc>>,
1612}
1613
1614impl std::fmt::Debug for TokenBuilder {
1615 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1616 f.write_str("TokenBuilder { .. }")
1617 }
1618}
1619
1620impl TokenBuilder {
1621 pub fn new(login_id: String) -> Self {
1623 Self {
1624 login_id,
1625 extra_data: None,
1626 device: None,
1627 login_type: None,
1628 nonce: None,
1629 expire_time: None,
1630 }
1631 }
1632
1633 pub fn extra_data(mut self, data: serde_json::Value) -> Self {
1635 self.extra_data = Some(data);
1636 self
1637 }
1638
1639 pub fn device(mut self, device: impl Into<String>) -> Self {
1641 self.device = Some(device.into());
1642 self
1643 }
1644
1645 pub fn login_type(mut self, login_type: impl Into<String>) -> Self {
1647 self.login_type = Some(login_type.into());
1648 self
1649 }
1650
1651 pub fn nonce(mut self, nonce: impl Into<String>) -> Self {
1654 self.nonce = Some(nonce.into());
1655 self
1656 }
1657
1658 pub fn expire_at(mut self, expire_time: chrono::DateTime<chrono::Utc>) -> Self {
1660 self.expire_time = Some(expire_time);
1661 self
1662 }
1663
1664 pub fn expire_at_unix(mut self, unix_seconds: i64) -> Self {
1666 self.expire_time = chrono::DateTime::from_timestamp(unix_seconds, 0);
1667 self
1668 }
1669
1670 #[deprecated(note = "use expire_at()")]
1673 pub fn expire_time(self, expire_time: chrono::DateTime<chrono::Utc>) -> Self {
1674 self.expire_at(expire_time)
1675 }
1676
1677 pub async fn login<T: LoginId>(self, login_id: Option<T>) -> SaTokenResult<TokenValue> {
1682 let manager = StpUtil::try_get_manager()?;
1683 let final_login_id = match login_id {
1684 Some(id) => id.to_login_id(),
1685 None => self.login_id,
1686 };
1687 manager
1688 .login_with_options(
1689 final_login_id,
1690 self.login_type,
1691 self.device,
1692 self.extra_data,
1693 self.nonce,
1694 self.expire_time,
1695 )
1696 .await
1697 }
1698}
1699
1700#[cfg(test)]
1701mod tests {
1702 use super::*;
1703
1704 #[test]
1705 fn test_token_format_validation() {
1706 assert!(StpUtil::is_valid_token_format("1234567890abcdef"));
1707 assert!(!StpUtil::is_valid_token_format(""));
1708 assert!(!StpUtil::is_valid_token_format("short"));
1709 }
1710
1711 #[test]
1712 fn test_create_token() {
1713 let token = StpUtil::create_token("test-token-123");
1714 assert_eq!(token.as_str(), "test-token-123");
1715 }
1716}