From e8bbc363640bc58b4f47664ee321ab59da45bea8 Mon Sep 17 00:00:00 2001 From: iven Date: Sun, 17 May 2026 12:54:34 +0800 Subject: [PATCH] =?UTF-8?q?perf(auth):=20JWT=20=E6=9D=83=E9=99=90=E7=BC=93?= =?UTF-8?q?=E5=AD=98=20RwLock=20=E6=9B=BF=E6=8D=A2=E4=B8=BA=20DashMap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit USER_SCOPE_CACHE 从 LazyLock> 改为 LazyLock, 消除读写锁竞争,提升高并发场景下的认证中间件吞吐量。 过期条目淘汰逻辑改用 DashMap::retain,无需手动获取 write lock。 --- crates/erp-auth/Cargo.toml | 1 + crates/erp-auth/src/middleware/jwt_auth.rs | 37 +++++++++++----------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/crates/erp-auth/Cargo.toml b/crates/erp-auth/Cargo.toml index fd90484..4db2620 100644 --- a/crates/erp-auth/Cargo.toml +++ b/crates/erp-auth/Cargo.toml @@ -26,3 +26,4 @@ cbc.workspace = true hex.workspace = true base64 = "0.22" redis.workspace = true +dashmap.workspace = true diff --git a/crates/erp-auth/src/middleware/jwt_auth.rs b/crates/erp-auth/src/middleware/jwt_auth.rs index 9c3f3a4..caa65cc 100644 --- a/crates/erp-auth/src/middleware/jwt_auth.rs +++ b/crates/erp-auth/src/middleware/jwt_auth.rs @@ -2,6 +2,7 @@ use axum::body::Body; use axum::http::Request; use axum::middleware::Next; use axum::response::Response; +use dashmap::DashMap; use erp_core::error::AppError; use erp_core::request_info::REQUEST_INFO; use erp_core::request_info::RequestInfo; @@ -12,11 +13,11 @@ use crate::service::token_service::TokenService; type DeptIds = Vec; type DataScopes = std::collections::HashMap; type ScopeCacheEntry = (DeptIds, DataScopes, std::time::Instant); -type ScopeCacheMap = std::collections::HashMap; /// 用户权限数据缓存(user_id -> (department_ids, data_scopes, cached_at)) -static USER_SCOPE_CACHE: std::sync::LazyLock> = - std::sync::LazyLock::new(|| std::sync::RwLock::new(std::collections::HashMap::new())); +/// DashMap 分片并发,读写无锁竞争 +static USER_SCOPE_CACHE: std::sync::LazyLock> = + std::sync::LazyLock::new(DashMap::new); const SCOPE_CACHE_TTL: std::time::Duration = std::time::Duration::from_secs(60); @@ -76,16 +77,17 @@ pub async fn jwt_auth_middleware_fn( } // 查询用户所属部门 ID 列表 + 权限数据范围(带 60 秒缓存) - let cached = { - let cache = USER_SCOPE_CACHE.read().unwrap(); - cache.get(&claims.sub).and_then(|(depts, scopes, at)| { - if at.elapsed() < SCOPE_CACHE_TTL { - Some((depts.clone(), scopes.clone())) - } else { - None - } - }) - }; + let cached = USER_SCOPE_CACHE.get(&claims.sub).and_then(|entry| { + let (_, _, at) = entry.value(); + if at.elapsed() < SCOPE_CACHE_TTL { + let (depts, scopes, _) = entry.value(); + Some((depts.clone(), scopes.clone())) + } else { + drop(entry); + USER_SCOPE_CACHE.remove(&claims.sub); + None + } + }); let (department_ids, permission_data_scopes) = match cached { Some(hit) => hit, None => fetch_and_cache_scopes(claims.sub, claims.tid, &db).await, @@ -207,15 +209,14 @@ async fn fetch_and_cache_scopes( Some(conn) => fetch_permission_data_scopes(user_id, tenant_id, conn).await, None => std::collections::HashMap::new(), }; - let mut cache = USER_SCOPE_CACHE.write().unwrap(); - cache.insert( + USER_SCOPE_CACHE.insert( user_id, (depts.clone(), scopes.clone(), std::time::Instant::now()), ); - // 惰性淘汰过期条目,防止 HashMap 无限增长 - if cache.len() > 500 { + // 惰性淘汰过期条目,防止 DashMap 无限增长 + if USER_SCOPE_CACHE.len() > 500 { let now = std::time::Instant::now(); - cache.retain(|_, (_, _, at)| now.duration_since(*at) < SCOPE_CACHE_TTL); + USER_SCOPE_CACHE.retain(|_, (_, _, at)| now.duration_since(*at) < SCOPE_CACHE_TTL); } (depts, scopes) }