Skip to main content

sa_token_core/sso/
slo.rs

1// Author: 金书记 | Author: Jin Shuji
2//! SLO callback notifier.
3//! SLO 回调通知器。
4
5use async_trait::async_trait;
6
7use crate::error::SaTokenResult;
8
9/// Notifies client apps on single logout.
10/// 单点登出时通知客户端应用。
11#[async_trait]
12pub trait SloNotifier: Send + Sync {
13    /// Notify one client logout URL.
14    /// 通知单个客户端登出 URL。
15    async fn notify_logout(&self, logout_url: &str, login_id: &str) -> SaTokenResult<()>;
16}
17
18/// Default: do not call the network.
19/// 默认:不发起网络请求。
20pub struct NoopSloNotifier;
21
22#[async_trait]
23impl SloNotifier for NoopSloNotifier {
24    async fn notify_logout(&self, _logout_url: &str, _login_id: &str) -> SaTokenResult<()> {
25        Ok(())
26    }
27}
28
29impl std::fmt::Debug for NoopSloNotifier {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        f.write_str("NoopSloNotifier { .. }")
32    }
33}
34
35/// HTTP POST form notifier (compiled only with `sso-http`).
36/// HTTP POST 表单通知器(仅 `sso-http` 时编译)。
37#[cfg(feature = "sso-http")]
38pub struct HttpSloNotifier {
39    client: reqwest::Client,
40}
41
42#[cfg(feature = "sso-http")]
43impl HttpSloNotifier {
44    /// Create with a default HTTP client.
45    /// 使用默认 HTTP 客户端创建。
46    pub fn new() -> Self {
47        Self {
48            client: reqwest::Client::new(),
49        }
50    }
51}
52
53#[cfg(feature = "sso-http")]
54impl Default for HttpSloNotifier {
55    fn default() -> Self {
56        Self::new()
57    }
58}
59
60#[cfg(feature = "sso-http")]
61#[async_trait]
62impl SloNotifier for HttpSloNotifier {
63    async fn notify_logout(&self, logout_url: &str, login_id: &str) -> SaTokenResult<()> {
64        let resp = self
65            .client
66            .post(logout_url)
67            .form(&[("loginId", login_id)])
68            .send()
69            .await
70            .map_err(|e| {
71                crate::error::SaTokenError::StorageError(format!("SLO notify failed: {e}"))
72            })?;
73        if resp.status().is_success() {
74            Ok(())
75        } else {
76            Err(crate::error::SaTokenError::StorageError(format!(
77                "SLO notify HTTP {}",
78                resp.status()
79            )))
80        }
81    }
82}