r_token/
memory.rs

1use crate::RTokenError;
2use crate::models::RTokenInfo;
3use chrono::Utc;
4use std::{
5    collections::HashMap,
6    sync::{
7        Arc, Mutex,
8        atomic::{AtomicU64, Ordering},
9    },
10};
11
12/// ## 日本語
13///
14/// 現在時刻の Unix epoch ミリ秒を返します。
15///
16/// ## English
17///
18/// Returns the current Unix epoch milliseconds.
19fn now_ms() -> u64 {
20    u64::try_from(Utc::now().timestamp_millis()).unwrap_or(0)
21}
22
23/// ## 日本語
24///
25/// `now_ms + ttl_seconds` をミリ秒で安全に加算します(飽和演算)。
26///
27/// ## English
28///
29/// Computes `now_ms + ttl_seconds` in milliseconds with saturation.
30fn add_ttl_ms(now_ms: u64, ttl_seconds: u64) -> u64 {
31    let ttl_ms = (ttl_seconds as u128).saturating_mul(1000);
32    (now_ms as u128)
33        .saturating_add(ttl_ms)
34        .min(u64::MAX as u128) as u64
35}
36
37/// ## 日本語
38///
39/// 自動掃除を実行する最小間隔(ミリ秒)。
40///
41/// ## English
42///
43/// Minimum interval for automatic pruning (milliseconds).
44const PRUNE_INTERVAL_MS: u64 = 60_000;
45/// ## 日本語
46///
47/// 自動掃除を試みる最小ストアサイズ。
48///
49/// ## English
50///
51/// Minimum store size that triggers auto-pruning.
52const PRUNE_MIN_SIZE: usize = 1024;
53
54/// ## 日本語
55///
56/// 認証 token の発行・保存・失効を行うマネージャです。
57///
58/// actix-web のアプリケーション state(例:`web::Data<RTokenManager>`)に保持する想定で、
59/// 内部では `Arc<Mutex<...>>` を使って状態を共有します。そのため `Clone` は同じストアへの
60/// ハンドルを増やすだけです。
61///
62/// token は UUID v4 文字列として生成され、次と紐づきます:
63/// - ユーザー ID(`String`)
64/// - 有効期限(Unix epoch ミリ秒)
65///
66/// ## English
67///
68/// Issues, stores, and revokes authentication tokens.
69///
70/// This type is designed to be stored in actix-web application state
71/// (e.g. `web::Data<RTokenManager>`). Internally it uses an `Arc<Mutex<...>>`,
72/// so `Clone` creates another handle to the same shared store.
73///
74/// Tokens are generated as UUID v4 strings. Each token is associated with:
75/// - a user id (`String`)
76/// - an expiration timestamp (Unix epoch milliseconds)
77#[derive(Clone)]
78pub struct RTokenManager {
79    /// ## 日本語
80    ///
81    /// インメモリの token ストア。
82    ///
83    /// ## English
84    ///
85    /// In-memory token store.
86    store: Arc<Mutex<HashMap<String, RTokenInfo>>>,
87    /// ## 日本語
88    ///
89    /// 最後に自動掃除を実行した時刻(ミリ秒)。
90    ///
91    /// ## English
92    ///
93    /// The last time auto-pruning ran (milliseconds).
94    last_prune_ms: Arc<AtomicU64>,
95}
96
97impl RTokenManager {
98    /// ## 日本語
99    ///
100    /// 空のマネージャを作成します。
101    ///
102    /// ## English
103    ///
104    /// Creates an empty manager.
105    pub fn new() -> Self {
106        Self {
107            store: Arc::new(Mutex::new(HashMap::new())),
108            last_prune_ms: Arc::new(AtomicU64::new(0)),
109        }
110    }
111
112    /// ## 日本語
113    ///
114    /// 指定ユーザー ID の新しい token を発行します。
115    ///
116    /// `expire_time` は TTL(秒)として扱います。保存された有効期限が現在時刻より過去であれば、
117    /// token は無効とみなされます。
118    ///
119    /// 内部 mutex が poisoned の場合は [`RTokenError::MutexPoisoned`] を返します。
120    ///
121    /// ## English
122    ///
123    /// Issues a new token for the given user id.
124    ///
125    /// `expire_time` is treated as TTL in seconds. The token will be considered invalid
126    /// once the stored expiration timestamp is earlier than the current time.
127    ///
128    /// Returns [`RTokenError::MutexPoisoned`] if the internal mutex is poisoned.
129    pub fn login(&self, id: &str, expire_time: u64) -> Result<String, RTokenError> {
130        // 日本語: token は UUID v4 文字列で生成する
131        // English: Tokens are generated as UUID v4 strings
132        let token = uuid::Uuid::new_v4().to_string();
133
134        // 日本語: expire_time は秒 TTL として扱い、現在時刻から期限 (ms) を計算する
135        // English: Treat expire_time as TTL seconds and compute deadline in milliseconds
136        let expire_time = add_ttl_ms(now_ms(), expire_time);
137
138        // 日本語: token と紐づく情報(user_id / expire_at / roles)を作る
139        // English: Build token info (user_id / expire_at / roles)
140        let info = RTokenInfo {
141            user_id: id.to_string(),
142            expire_at: expire_time,
143            roles: Vec::new(),
144        };
145
146        // 日本語: mutex をロックしてストアに保存する(poisoned はライブラリのエラーに変換)
147        // English: Lock the store mutex and insert (map poisoned to library error)
148        let now_ms = now_ms();
149        let mut store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
150        store.insert(token.clone(), info);
151        self.maybe_prune(&mut store, now_ms);
152        Ok(token)
153    }
154
155    #[cfg(feature = "rbac")]
156    /// ## 日本語
157    ///
158    /// 指定ユーザー ID と役割(roles)を紐づけた新しい token を発行します(RBAC 有効時)。
159    ///
160    /// `expire_time` は TTL(秒)として扱います。
161    ///
162    /// ## English
163    ///
164    /// Issues a new token for the given user id and roles (RBAC enabled).
165    ///
166    /// `expire_time` is treated as TTL in seconds.
167    pub fn login_with_roles(
168        &self,
169        id: &str,
170        expire_time: u64,
171        role: impl Into<Vec<String>>,
172    ) -> Result<String, RTokenError> {
173        // 日本語: token は UUID v4 文字列で生成する
174        // English: Tokens are generated as UUID v4 strings
175        let token = uuid::Uuid::new_v4().to_string();
176
177        // 日本語: expire_time は秒 TTL として扱い、現在時刻から期限 (ms) を計算する
178        // English: Treat expire_time as TTL seconds and compute deadline in milliseconds
179        let expire_time = add_ttl_ms(now_ms(), expire_time);
180
181        // 日本語: roles を含む token 情報を作って保存する
182        // English: Build token info including roles and store it
183        let info = RTokenInfo {
184            user_id: id.to_string(),
185            expire_at: expire_time,
186            roles: role.into(),
187        };
188        let now_ms = now_ms();
189        let mut store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
190        store.insert(token.clone(), info);
191        self.maybe_prune(&mut store, now_ms);
192        Ok(token)
193    }
194
195    // pub fn set_role(&self, token: &str, role: impl Into<Vec<String>>) -> Result<(), RTokenError> {
196    #[cfg(feature = "rbac")]
197    /// ## 日本語
198    ///
199    /// 既存 token の roles を更新します(RBAC 有効時)。
200    ///
201    /// token が存在しない場合でも成功として扱います(冪等)。
202    ///
203    /// ## English
204    ///
205    /// Updates roles for an existing token (RBAC enabled).
206    ///
207    /// This operation is idempotent: if the token does not exist, it is treated as success.
208    pub fn set_roles(&self, token: &str, roles: impl Into<Vec<String>>) -> Result<(), RTokenError> {
209        // 日本語: まずストアをロックする
210        // English: Lock the store first
211        let mut store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
212        if let Some(info) = store.get_mut(token) {
213            // 日本語: token が存在する場合のみ roles を更新する
214            // English: Update roles only when the token exists
215            info.roles = roles.into();
216        }
217        Ok(())
218    }
219
220    #[cfg(feature = "rbac")]
221    /// ## 日本語
222    ///
223    /// token に紐づく roles を返します(RBAC 有効時)。
224    ///
225    /// token が存在しない場合は `Ok(None)` を返します。
226    ///
227    /// ## English
228    ///
229    /// Returns roles associated with a token (RBAC enabled).
230    ///
231    /// Returns `Ok(None)` if the token does not exist.
232    pub fn get_roles(&self, token: &str) -> Result<Option<Vec<String>>, RTokenError> {
233        // 日本語: 読み取りのためストアをロックする
234        // English: Lock the store for reading
235        let store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
236        // 日本語: Vec を返すため clone する(ストア内部を露出しない)
237        // English: Clone the Vec to avoid exposing internal storage
238        Ok(store.get(token).map(|info| info.roles.clone()))
239    }
240
241    /// ## 日本語
242    ///
243    /// token をインメモリストアから削除して失効させます。
244    ///
245    /// この操作は冪等です。存在しない token を削除しても成功として扱います。
246    /// 内部 mutex が poisoned の場合は [`RTokenError::MutexPoisoned`] を返します。
247    ///
248    /// ## English
249    ///
250    /// Revokes a token by removing it from the in-memory store.
251    ///
252    /// This operation is idempotent: removing a non-existing token is treated as success.
253    /// Returns [`RTokenError::MutexPoisoned`] if the internal mutex is poisoned.
254    pub fn logout(&self, token: &str) -> Result<(), RTokenError> {
255        // 日本語: remove は「存在しない token」でも何もしないため冪等
256        // English: remove is idempotent (no-op for non-existing tokens)
257        self.store
258            .lock()
259            .map_err(|_| RTokenError::MutexPoisoned)?
260            .remove(token);
261        Ok(())
262    }
263
264    /// ## 日本語
265    ///
266    /// token に保存されている有効期限(Unix epoch ミリ秒)を返します。
267    ///
268    /// token が存在しない場合は `Ok(None)` を返します。本メソッドは token の期限切れ判定は
269    /// 行いません。
270    ///
271    /// ## English
272    ///
273    /// Returns the stored expiration timestamp for a token (milliseconds since Unix epoch).
274    ///
275    /// Returns `Ok(None)` if the token does not exist. This method does not validate
276    /// whether the token has already expired.
277    pub fn expires_at(&self, token: &str) -> Result<Option<u64>, RTokenError> {
278        // 日本語: token の存在確認のみ(期限切れ判定はしない)
279        // English: Only checks existence (does not validate expiration)
280        let store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
281        Ok(store.get(token).map(|info| info.expire_at))
282    }
283
284    /// ## 日本語
285    ///
286    /// token の残り TTL(秒)を返します。
287    ///
288    /// 返り値:
289    /// - token が存在しない:`Ok(None)`
290    /// - token がすでに期限切れ:`Ok(Some(0))`(本メソッドでは削除しません)
291    ///
292    /// ## English
293    ///
294    /// Returns the remaining TTL in seconds for a token.
295    ///
296    /// Returns:
297    /// - `Ok(None)` when the token does not exist
298    /// - `Ok(Some(0))` when the token is already expired (it is not removed here)
299    pub fn ttl_seconds(&self, token: &str) -> Result<Option<i64>, RTokenError> {
300        // 日本語: 現在時刻 (ms) と保存された expire_at (ms) の差から残り秒数を計算する
301        // English: Compute remaining seconds from now_ms and stored expire_at (milliseconds)
302        let now_ms = now_ms();
303        let store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
304        let Some(expire_at) = store.get(token).map(|info| info.expire_at) else {
305            return Ok(None);
306        };
307
308        if expire_at <= now_ms {
309            return Ok(Some(0));
310        }
311
312        let remaining_ms = expire_at - now_ms;
313        // 日本語: ms を秒に変換(端数は切り上げ)
314        // English: Convert ms to seconds (ceil)
315        let remaining_seconds = remaining_ms.div_ceil(1000) as i64;
316        Ok(Some(remaining_seconds))
317    }
318
319    /// ## 日本語
320    ///
321    /// token の有効期限を `now + ttl_seconds` に延長します。
322    ///
323    /// 返り値:
324    /// - token が存在し、期限切れでない:`Ok(true)`
325    /// - token が存在しない、または期限切れ:`Ok(false)`(期限切れの場合は削除します)
326    ///
327    /// ## English
328    ///
329    /// Extends a token's lifetime to `now + ttl_seconds`.
330    ///
331    /// Returns:
332    /// - `Ok(true)` if the token exists and is not expired
333    /// - `Ok(false)` if the token does not exist or is expired (expired tokens are removed)
334    pub fn renew(&self, token: &str, ttl_seconds: u64) -> Result<bool, RTokenError> {
335        // 日本語: now + ttl_seconds で新しい expire_at (ms) を計算する
336        // English: Compute new expire_at (ms) as now + ttl_seconds
337        let expire_at = add_ttl_ms(now_ms(), ttl_seconds);
338
339        // 日本語: 対象 token を更新するためストアをロックする
340        // English: Lock the store to update the token
341        let mut store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
342        let Some(info) = store.get_mut(token) else {
343            return Ok(false);
344        };
345
346        // 日本語: 期限切れは renew 失敗として扱い、ストアから削除する
347        // English: Treat expired token as failure and remove it from store
348        if info.expire_at < now_ms() {
349            store.remove(token);
350            return Ok(false);
351        }
352
353        // 日本語: 有効な token の期限を更新する
354        // English: Update expiration for valid token
355        info.expire_at = expire_at;
356        Ok(true)
357    }
358
359    /// ## 日本語
360    ///
361    /// 同じユーザー(および roles)に対して新しい token を発行し、古い token を失効させます。
362    ///
363    /// 新しい token の TTL は「現在から `ttl_seconds`」になります。
364    ///
365    /// 古い token が存在しない、または期限切れの場合は `Ok(None)` を返します(期限切れの場合は
366    /// 削除します)。
367    ///
368    /// ## English
369    ///
370    /// Issues a new token for the same user (and roles) and revokes the old token.
371    ///
372    /// The new token will have a lifetime of `ttl_seconds` from now.
373    ///
374    /// Returns `Ok(None)` if the old token does not exist or is expired (expired tokens
375    /// are removed).
376    pub fn rotate(&self, token: &str, ttl_seconds: u64) -> Result<Option<String>, RTokenError> {
377        // 日本語: 新 token の期限を now + ttl_seconds で計算する
378        // English: Compute new token expiration as now + ttl_seconds
379        let expire_at = add_ttl_ms(now_ms(), ttl_seconds);
380
381        // 日本語: old token の情報を参照して新 token に引き継ぐため clone する
382        // English: Clone old info so we can reuse it for the new token
383        let mut store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
384        let Some(info) = store.get(token).cloned() else {
385            return Ok(None);
386        };
387
388        // 日本語: old token が期限切れなら削除して None を返す
389        // English: If old token expired, remove it and return None
390        if info.expire_at < now_ms() {
391            store.remove(token);
392            return Ok(None);
393        }
394
395        // 日本語: 新 token を生成して情報を引き継ぐ(user_id / roles)
396        // English: Generate a new token and carry over user_id / roles
397        let new_token = uuid::Uuid::new_v4().to_string();
398        let new_info = RTokenInfo {
399            user_id: info.user_id,
400            expire_at,
401            roles: info.roles,
402        };
403
404        // 日本語: old token を削除し、新 token を追加する
405        // English: Remove old token and insert the new token
406        store.remove(token);
407        store.insert(new_token.clone(), new_info);
408        Ok(Some(new_token))
409    }
410
411    /// ## 日本語
412    ///
413    /// インメモリストアから期限切れの token を削除し、削除した件数を返します。
414    ///
415    /// ## English
416    ///
417    /// Removes expired tokens from the in-memory store and returns how many were removed.
418    pub fn prune_expired(&self) -> Result<usize, RTokenError> {
419        // 日本語: retain を使って期限切れのエントリを一括削除する
420        // English: Use retain to bulk-remove expired entries
421        let now = now_ms();
422        let mut store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
423
424        let original_len = store.len();
425        store.retain(|_token, info| info.expire_at >= now);
426        Ok(original_len - store.len())
427    }
428
429    /// ## 日本語
430    ///
431    /// token を検証し、有効であれば紐づくユーザー ID を返します。
432    ///
433    /// 振る舞い:
434    /// - token が存在し、期限切れでない:`Ok(Some(user_id))`
435    /// - token が存在しない、または期限切れ:`Ok(None)`
436    /// - 期限切れ token は検証時にストアから削除されます
437    ///
438    /// ## English
439    ///
440    /// Validates a token and returns the associated user id if present.
441    ///
442    /// Behavior:
443    /// - Returns `Ok(Some(user_id))` when the token exists and is not expired.
444    /// - Returns `Ok(None)` when the token does not exist or is expired.
445    /// - Expired tokens are removed from the in-memory store during validation.
446    pub fn validate(&self, token: &str) -> Result<Option<String>, RTokenError> {
447        #[cfg(feature = "rbac")]
448        {
449            Ok(self
450                .validate_with_roles(token)?
451                .map(|(user_id, _roles)| user_id))
452        }
453
454        #[cfg(not(feature = "rbac"))]
455        {
456            // 日本語: 検証時は期限切れを掃除するため書き込みロックを取る
457            // English: Take a write lock so we can remove expired tokens during validation
458            let mut store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
459            let Some(info) = store.get(token) else {
460                return Ok(None);
461            };
462
463            // 日本語: 期限切れなら削除して無効扱いにする
464            // English: If expired, remove and treat as invalid
465            if info.expire_at < now_ms() {
466                store.remove(token);
467                return Ok(None);
468            }
469
470            // 日本語: 有効 token の user_id を返す
471            // English: Return user_id for a valid token
472            Ok(Some(info.user_id.clone()))
473        }
474    }
475
476    #[cfg(feature = "rbac")]
477    /// ## 日本語
478    ///
479    /// token を検証し、ユーザー ID と roles を返します(RBAC 有効時)。
480    ///
481    /// 期限切れの扱いは [`RTokenManager::validate`] と同じです。
482    ///
483    /// ## English
484    ///
485    /// Validates a token and returns both user id and roles (RBAC enabled).
486    ///
487    /// This has the same expiration behavior as [`RTokenManager::validate`].
488    pub fn validate_with_roles(
489        &self,
490        token: &str,
491    ) -> Result<Option<(String, Vec<String>)>, RTokenError> {
492        // 日本語: 検証時に期限切れの削除があり得るため書き込みロックを取る
493        // English: Take a write lock because we may remove expired tokens
494        let mut store = self.store.lock().map_err(|_| RTokenError::MutexPoisoned)?;
495        let Some(info) = store.get(token) else {
496            return Ok(None);
497        };
498
499        // 日本語: 期限切れなら削除して無効扱いにする
500        // English: If expired, remove and treat as invalid
501        if info.expire_at < now_ms() {
502            store.remove(token);
503            return Ok(None);
504        }
505
506        // 日本語: user_id と roles を返す(clone して内部を露出しない)
507        // English: Return user_id and roles (clone to avoid exposing internals)
508        Ok(Some((info.user_id.clone(), info.roles.clone())))
509    }
510
511    /// ## 日本語
512    ///
513    /// 条件を満たす場合のみ期限切れ token を掃除します。
514    ///
515    /// ## English
516    ///
517    /// Prunes expired tokens only when the thresholds are met.
518    fn maybe_prune(&self, store: &mut HashMap<String, RTokenInfo>, now_ms: u64) {
519        if store.len() < PRUNE_MIN_SIZE {
520            return;
521        }
522
523        let last = self.last_prune_ms.load(Ordering::Relaxed);
524        if now_ms.saturating_sub(last) < PRUNE_INTERVAL_MS {
525            return;
526        }
527
528        self.last_prune_ms.store(now_ms, Ordering::Relaxed);
529        store.retain(|_token, info| info.expire_at >= now_ms);
530    }
531}
532
533impl Default for RTokenManager {
534    fn default() -> Self {
535        Self::new()
536    }
537}
538
539/// ## 日本語
540///
541/// actix-web / axum から抽出される認証済みユーザーコンテキストです。
542///
543/// 抽出が成功した場合:
544/// - `id` は [`RTokenManager::login`] に渡したユーザー ID
545/// - `token` はリクエストに含まれていた token の生文字列
546///
547/// token は `Authorization` header から読み取ります。次の形式に対応します:
548/// - `Authorization: <token>`
549/// - `Authorization: Bearer <token>`
550///
551/// ## English
552///
553/// An authenticated request context extracted from actix-web / axum.
554///
555/// If extraction succeeds, `id` is the user id previously passed to
556/// [`RTokenManager::login`], and `token` is the original token from the request.
557///
558/// The token is read from `Authorization` header. Both of the following formats
559/// are accepted:
560/// - `Authorization: <token>`
561/// - `Authorization: Bearer <token>`
562#[cfg(any(feature = "actix", feature = "axum"))]
563#[derive(Debug)]
564pub struct RUser {
565    /// ## 日本語
566    ///
567    /// token に紐づくユーザー ID。
568    ///
569    /// ## English
570    ///
571    /// The user id associated with the token.
572    pub id: String,
573
574    /// ## 日本語
575    ///
576    /// リクエストに含まれていた token の生文字列。
577    ///
578    /// ## English
579    ///
580    /// The raw token string from the request.
581    pub token: String,
582    #[cfg(feature = "rbac")]
583    /// ## 日本語
584    ///
585    /// token に紐づく roles(RBAC 有効時)。
586    ///
587    /// ## English
588    ///
589    /// Roles associated with the token (RBAC enabled).
590    pub roles: Vec<String>,
591}
592
593#[cfg(feature = "rbac")]
594impl RUser {
595    /// ## 日本語
596    ///
597    /// 指定した role を持つかどうかを返します。
598    ///
599    /// ## English
600    ///
601    /// Returns whether the user has the given role.
602    pub fn has_role(&self, role: &str) -> bool {
603        self.roles.iter().any(|r| r == role)
604    }
605}
606
607/// ## 日本語
608///
609/// actix-web のリクエストから [`RUser`] を抽出します。
610///
611/// 失敗時:
612/// - 500:`app_data` にマネージャが無い、または mutex が poisoned
613/// - 401:token が無い/無効/期限切れ
614///
615/// ## English
616///
617/// Extracts [`RUser`] from an actix-web request.
618///
619/// Failure modes:
620/// - 500: manager is missing from `app_data`, or mutex is poisoned
621/// - 401: token is missing, invalid, or expired
622#[cfg(feature = "actix")]
623impl actix_web::FromRequest for RUser {
624    type Error = actix_web::Error;
625    type Future = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Self, Self::Error>>>>;
626
627    fn from_request(
628        req: &actix_web::HttpRequest,
629        _payload: &mut actix_web::dev::Payload,
630    ) -> Self::Future {
631        use actix_web::web;
632
633        let manager = match req.app_data::<web::Data<RTokenManager>>() {
634            Some(m) => m.clone(),
635            None => {
636                return Box::pin(async {
637                    Err(actix_web::error::ErrorInternalServerError(
638                        "Token manager not found",
639                    ))
640                });
641            }
642        };
643        let token = match crate::extract_token_from_request(req) {
644            Some(token) => token,
645            None => {
646                return Box::pin(async {
647                    Err(actix_web::error::ErrorUnauthorized("Unauthorized"))
648                });
649            }
650        };
651
652        Box::pin(async move {
653            #[cfg(feature = "rbac")]
654            {
655                let token_for_check = token.clone();
656                let manager = manager.clone();
657                let user_info = actix_web::rt::task::spawn_blocking(move || {
658                    manager.validate_with_roles(&token_for_check)
659                })
660                .await
661                .map_err(|_| actix_web::error::ErrorInternalServerError("Mutex poisoned"))?
662                .map_err(|_| actix_web::error::ErrorInternalServerError("Mutex poisoned"))?;
663
664                if let Some((user_id, roles)) = user_info {
665                    return Ok(RUser {
666                        id: user_id,
667                        token,
668                        roles,
669                    });
670                }
671
672                Err(actix_web::error::ErrorUnauthorized("Invalid token"))
673            }
674
675            #[cfg(not(feature = "rbac"))]
676            {
677                let token_for_check = token.clone();
678                let manager = manager.clone();
679                let user_id =
680                    actix_web::rt::task::spawn_blocking(move || manager.validate(&token_for_check))
681                        .await
682                        .map_err(|_| actix_web::error::ErrorInternalServerError("Mutex poisoned"))?
683                        .map_err(|_| {
684                            actix_web::error::ErrorInternalServerError("Mutex poisoned")
685                        })?;
686
687                if let Some(user_id) = user_id {
688                    return Ok(RUser { id: user_id, token });
689                }
690
691                Err(actix_web::error::ErrorUnauthorized("Invalid token"))
692            }
693        })
694    }
695}