Skip to main content

sa_token_core/context/
mod.rs

1// Author: 金书记
2//
3//! 上下文模块 - 用于在请求处理过程中传递 token 信息
4//!
5//! - **`tokio::task_local!`**:跨 `await`、跨 Tokio worker 线程仍与同一异步任务绑定(推荐)。
6//! - **`thread_local`**:兼容旧代码与同步路径([`SaTokenContext::set_current`] / [`SaTokenContext::clear`])。
7//!
8//! Context module — carries token info during a request.
9//! **`tokio::task_local!`**: stays bound to the same logical async task across awaits/workers (preferred).
10//! **`thread_local`**: backward-compatible synchronous path (`set_current` / `clear`).
11
12use std::cell::RefCell;
13use std::future::Future;
14use std::sync::Arc;
15
16use crate::token::{TokenInfo, TokenValue};
17
18thread_local! {
19    static TLS_CTX: RefCell<Option<SaTokenContext>> = const { RefCell::new(None) };
20}
21
22tokio::task_local! {
23    static TASK_CTX: SaTokenContext;
24}
25
26/// sa-token 上下文 | sa-token Context
27///
28/// # 字段说明 | Field Description
29/// - `token`: 当前请求的 token | Current request's token
30/// - `token_info`: Token 详细信息 | Token detailed information
31/// - `login_id`: 登录用户 ID | Logged-in user ID
32#[derive(Debug, Clone)]
33pub struct SaTokenContext {
34    /// 当前请求的 token | Current request's token
35    pub token: Option<TokenValue>,
36
37    /// 当前请求的 token 信息 | Current request's token info
38    pub token_info: Option<Arc<TokenInfo>>,
39
40    /// 登录 ID | Login ID
41    pub login_id: Option<String>,
42}
43
44impl SaTokenContext {
45    pub fn new() -> Self {
46        Self {
47            token: None,
48            token_info: None,
49            login_id: None,
50        }
51    }
52
53    /// Bind `ctx` for the whole lifetime of `fut` (await-safe across worker threads).
54    /// 在 `fut` 全生命周期内绑定 `ctx`(跨 await / 跨 worker 仍有效)。
55    pub async fn scope<F, R>(ctx: SaTokenContext, fut: F) -> R
56    where
57        F: Future<Output = R>,
58    {
59        TASK_CTX.scope(ctx, fut).await
60    }
61
62    /// Clone of current context: **task-local first**, then thread-local fallback.
63    /// 当前上下文副本:**优先 task-local**,再回落 thread-local。
64    pub fn try_current() -> Option<SaTokenContext> {
65        match TASK_CTX.try_with(|c| c.clone()) {
66            Ok(c) => Some(c),
67            Err(_) => TLS_CTX.with(|c| c.borrow().clone()),
68        }
69    }
70
71    /// 设置当前上下文(thread-local 兼容路径)| Set current context (thread-local compat)
72    pub fn set_current(ctx: SaTokenContext) {
73        TLS_CTX.with(|c| {
74            *c.borrow_mut() = Some(ctx);
75        });
76    }
77
78    /// 获取当前上下文 | Get current context
79    pub fn get_current() -> Option<SaTokenContext> {
80        Self::try_current()
81    }
82
83    /// 清除当前上下文(thread-local 兼容路径)| Clear current context (thread-local compat)
84    pub fn clear() {
85        TLS_CTX.with(|c| {
86            *c.borrow_mut() = None;
87        });
88    }
89}
90
91impl Default for SaTokenContext {
92    fn default() -> Self {
93        Self::new()
94    }
95}