Cache Arc<TokenClaims> in JWT validation; bump Docker base images

JWT validation cache now stores Arc<TokenClaims> and validate_token
returns Arc<TokenClaims>. On a cache hit — the 99% path for every
authenticated request — the moka lookup was deep-cloning the whole
claims struct (5 Strings: sub, jti, username, email, role) on every
call. It is now a refcount bump. Read-only callers (admin middleware)
go through Deref and allocate nothing; the auth middleware clones only
the three fields it moves into CurrentUser (was 5 clones, now 3), and
the admin paths clone only role (was 5, now 1). A new test asserts the
hit path returns a pointer-equal Arc.

TokenServicePort::validate_token is the single trait method touched;
its only implementor is JwtTokenService and the only production callers
are the auth and admin middleware (the WOPI handler uses a separate
WopiTokenService).

Dockerfile: rust:1.94.1-alpine3.23 -> rust:1.96-alpine3.24 and
alpine:3.23.3 -> alpine:3.24.0 for the runtime stage.

https://claude.ai/code/session_0193Hff42gaA962wThxMGSd1
This commit is contained in:
Claude
2026-06-11 10:56:33 +00:00
parent 54c494419c
commit 23de7e503b
5 changed files with 55 additions and 19 deletions
+9 -2
View File
@@ -3,6 +3,7 @@ use crate::domain::entities::app_password::AppPassword;
use crate::domain::entities::device_code::DeviceCode;
use crate::domain::entities::session::Session;
use crate::domain::entities::user::User;
use std::sync::Arc;
use uuid::Uuid;
// ============================================================================
@@ -51,8 +52,14 @@ pub trait TokenServicePort: Send + Sync + 'static {
/// Generate an access token for a user
fn generate_access_token(&self, user: &User) -> Result<String, DomainError>;
/// Validate a token and extract its claims
fn validate_token(&self, token: &str) -> Result<TokenClaims, DomainError>;
/// Validate a token and extract its claims.
///
/// Returns `Arc<TokenClaims>` so the implementation's validation cache can
/// hand back a hot entry with a refcount bump instead of deep-cloning the
/// (multi-`String`) claims on every authenticated request. Callers that
/// only read fields go through `Deref`; the few that retain a field clone
/// just that one.
fn validate_token(&self, token: &str) -> Result<Arc<TokenClaims>, DomainError>;
/// Generate a refresh token
fn generate_refresh_token(&self) -> String;