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 /// 身份临时切换目标 login_id(对齐 Java switchTo)
44 pub switch_login_id: Option<String>,
45}
46
47impl SaTokenContext {
48 pub fn new() -> Self {
49 Self {
50 token: None,
51 token_info: None,
52 login_id: None,
53 switch_login_id: None,
54 }
55 }
56
57 /// Bind `ctx` for the whole lifetime of `fut` (await-safe across worker threads).
58 /// 在 `fut` 全生命周期内绑定 `ctx`(跨 await / 跨 worker 仍有效)。
59 pub async fn scope<F, R>(ctx: SaTokenContext, fut: F) -> R
60 where
61 F: Future<Output = R>,
62 {
63 TASK_CTX.scope(ctx, fut).await
64 }
65
66 /// Clone of current context: **task-local first**, then thread-local fallback.
67 /// 当前上下文副本:**优先 task-local**,再回落 thread-local。
68 pub fn try_current() -> Option<SaTokenContext> {
69 match TASK_CTX.try_with(|c| c.clone()) {
70 Ok(c) => Some(c),
71 Err(_) => TLS_CTX.with(|c| c.borrow().clone()),
72 }
73 }
74
75 /// 设置当前上下文(thread-local 兼容路径)| Set current context (thread-local compat)
76 pub fn set_current(ctx: SaTokenContext) {
77 TLS_CTX.with(|c| {
78 *c.borrow_mut() = Some(ctx);
79 });
80 }
81
82 /// 获取当前上下文 | Get current context
83 pub fn get_current() -> Option<SaTokenContext> {
84 Self::try_current()
85 }
86
87 /// 清除当前上下文(thread-local 兼容路径)| Clear current context (thread-local compat)
88 pub fn clear() {
89 TLS_CTX.with(|c| {
90 *c.borrow_mut() = None;
91 });
92 }
93}
94
95impl Default for SaTokenContext {
96 fn default() -> Self {
97 Self::new()
98 }
99}