sa_token_core/
same_token.rs1use std::time::Duration;
10
11use crate::error::{SaTokenError, SaTokenResult};
12use crate::util::StpUtil;
13
14pub const DEFAULT_HEADER: &str = "SA-SAME-TOKEN";
17
18fn ttl(timeout_secs: i64) -> Option<Duration> {
19 if timeout_secs > 0 {
20 Some(Duration::from_secs(timeout_secs as u64))
21 } else {
22 None
23 }
24}
25
26fn generate_token() -> SaTokenResult<String> {
27 crate::token::random_hex(32)
28}
29
30pub async fn get_token_nh() -> SaTokenResult<Option<String>> {
33 let manager = StpUtil::try_get_manager()?;
34 let key = manager.keys().same_token();
35 manager.dao().get_string(&key).await
36}
37
38pub async fn get_past_token_nh() -> SaTokenResult<Option<String>> {
41 let manager = StpUtil::try_get_manager()?;
42 let key = manager.keys().same_token_past();
43 manager.dao().get_string(&key).await
44}
45
46pub async fn get_token() -> SaTokenResult<String> {
49 if let Some(existing) = get_token_nh().await?
50 && !existing.is_empty()
51 {
52 return Ok(existing);
53 }
54 refresh_token().await
55}
56
57pub async fn is_valid(token: &str) -> SaTokenResult<bool> {
60 if token.is_empty() {
61 return Ok(false);
62 }
63 let current = get_token_nh().await?;
64 if current
65 .as_deref()
66 .is_some_and(|c| crate::http_basic::ct_eq(c.as_bytes(), token.as_bytes()))
67 {
68 return Ok(true);
69 }
70 let past = get_past_token_nh().await?;
71 Ok(past
72 .as_deref()
73 .is_some_and(|p| crate::http_basic::ct_eq(p.as_bytes(), token.as_bytes())))
74}
75
76pub async fn refresh_token() -> SaTokenResult<String> {
79 let manager = StpUtil::try_get_manager()?;
80 let timeout = manager.config.same_token_timeout;
81 let ttl_opt = ttl(timeout);
82 let dao = manager.dao();
83 let cur_key = manager.keys().same_token();
84 let past_key = manager.keys().same_token_past();
85
86 let current = dao.get_string(&cur_key).await?;
87 if let Some(ref cur) = current {
88 if !cur.is_empty() {
89 dao.set_string(&past_key, cur, ttl_opt).await?;
90 }
91 }
92
93 let next = generate_token()?;
94 let expected = current.as_deref().filter(|s| !s.is_empty());
95 let won = dao.cas(&cur_key, expected, &next, ttl_opt).await?;
96 if won {
97 return Ok(next);
98 }
99 dao.get_string(&cur_key)
102 .await?
103 .filter(|s| !s.is_empty())
104 .ok_or(SaTokenError::SameTokenInvalid)
105}
106
107pub async fn check_token(token: &str) -> SaTokenResult<()> {
110 if is_valid(token).await? {
111 Ok(())
112 } else {
113 Err(SaTokenError::SameTokenInvalid)
114 }
115}
116
117pub async fn check_current_request() -> SaTokenResult<()> {
120 let value = crate::context::SaTokenContext::try_current()
121 .and_then(|ctx| ctx.auth_meta().same_token)
122 .unwrap_or_default();
123 check_token(&value).await
124}