feat: add refresh cookie reader

This commit is contained in:
2026-04-21 13:34:54 +08:00
parent adaf514a1a
commit 39eb7a513c
12 changed files with 653 additions and 11 deletions

View File

@@ -1,11 +1,14 @@
use axum::{
Json,
extract::{Extension, Request, State},
http::{HeaderMap, StatusCode, header::AUTHORIZATION},
http::{
HeaderMap, StatusCode,
header::{AUTHORIZATION, COOKIE},
},
middleware::Next,
response::Response,
};
use platform_auth::{AccessTokenClaims, verify_access_token};
use platform_auth::{AccessTokenClaims, read_refresh_session_token, verify_access_token};
use serde_json::{Value, json};
use tracing::warn;
@@ -20,6 +23,11 @@ pub struct AuthenticatedAccessToken {
claims: AccessTokenClaims,
}
#[derive(Clone, Debug)]
pub struct RefreshSessionToken {
token: String,
}
impl AuthenticatedAccessToken {
pub fn new(claims: AccessTokenClaims) -> Self {
Self { claims }
@@ -30,6 +38,16 @@ impl AuthenticatedAccessToken {
}
}
impl RefreshSessionToken {
pub fn new(token: String) -> Self {
Self { token }
}
pub fn token(&self) -> &str {
&self.token
}
}
pub async fn require_bearer_auth(
State(state): State<AppState>,
mut request: Request,
@@ -69,6 +87,44 @@ pub async fn inspect_auth_claims(
)
}
pub async fn attach_refresh_session_token(
State(state): State<AppState>,
mut request: Request,
next: Next,
) -> Response {
if let Some(token) = request
.headers()
.get(COOKIE)
.and_then(|value| value.to_str().ok())
.and_then(|cookie_header| {
read_refresh_session_token(cookie_header, state.refresh_cookie_config())
})
{
request
.extensions_mut()
.insert(RefreshSessionToken::new(token));
}
next.run(request).await
}
pub async fn inspect_refresh_session_cookie(
State(state): State<AppState>,
Extension(request_context): Extension<RequestContext>,
request: Request,
) -> Json<Value> {
let maybe_token = request.extensions().get::<RefreshSessionToken>();
json_success_body(
Some(&request_context),
json!({
"cookieName": state.refresh_cookie_config().cookie_name(),
"present": maybe_token.is_some(),
"tokenLength": maybe_token.map(|token| token.token().len()),
}),
)
}
fn extract_bearer_token(headers: &HeaderMap) -> Result<String, AppError> {
let authorization = headers
.get(AUTHORIZATION)
@@ -88,7 +144,7 @@ fn extract_bearer_token(headers: &HeaderMap) -> Result<String, AppError> {
#[cfg(test)]
mod tests {
use super::extract_bearer_token;
use super::{RefreshSessionToken, extract_bearer_token};
use axum::{
http::{HeaderMap, HeaderValue, StatusCode, header::AUTHORIZATION},
response::IntoResponse,
@@ -116,4 +172,11 @@ mod tests {
assert_eq!(error.into_response().status(), StatusCode::UNAUTHORIZED);
}
#[test]
fn refresh_session_token_retains_original_value() {
let token = RefreshSessionToken::new("refresh-token-01".to_string());
assert_eq!(token.token(), "refresh-token-01");
}
}