feat: add refresh token rotation flow

This commit is contained in:
2026-04-21 15:27:04 +08:00
parent 70dbefda2b
commit 584a77e572
16 changed files with 1048 additions and 85 deletions

View File

@@ -1,20 +1,20 @@
use axum::{
Json,
extract::{Extension, State},
http::{HeaderMap, HeaderValue, StatusCode, header::SET_COOKIE},
http::{HeaderMap, StatusCode},
response::IntoResponse,
};
use module_auth::{PasswordEntryError, PasswordEntryInput};
use platform_auth::{
AccessTokenClaims, AccessTokenClaimsInput, AuthProvider, BindingStatus,
build_refresh_session_set_cookie, create_refresh_session_token, sign_access_token,
};
use serde::{Deserialize, Serialize};
use serde_json::json;
use time::OffsetDateTime;
use crate::{
api_response::json_success_body, http_error::AppError, request_context::RequestContext,
api_response::json_success_body,
auth_session::{
attach_set_cookie_header, build_refresh_session_cookie_header, create_password_auth_session,
},
http_error::AppError,
request_context::RequestContext,
state::AppState,
};
@@ -57,45 +57,20 @@ pub async fn password_entry(
})
.await
.map_err(map_password_entry_error)?;
let refresh_session_token = create_refresh_session_token();
let access_claims = AccessTokenClaims::from_input(
AccessTokenClaimsInput {
user_id: result.user.id.clone(),
session_id: refresh_session_token.clone(),
provider: AuthProvider::Password,
roles: vec!["user".to_string()],
token_version: result.user.token_version,
phone_verified: false,
binding_status: BindingStatus::Active,
display_name: Some(result.user.display_name.clone()),
},
state.auth_jwt_config(),
OffsetDateTime::now_utc(),
)
.map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_message(error.to_string())
})?;
let access_token =
sign_access_token(&access_claims, state.auth_jwt_config()).map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_message(error.to_string())
})?;
let refresh_cookie =
build_refresh_session_set_cookie(&refresh_session_token, state.refresh_cookie_config());
let signed_session = create_password_auth_session(&state, &result.user)?;
let mut headers = HeaderMap::new();
let set_cookie = HeaderValue::from_str(&refresh_cookie).map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR)
.with_message(format!("refresh cookie 头构造失败:{error}"))
})?;
headers.insert(SET_COOKIE, set_cookie);
attach_set_cookie_header(
&mut headers,
build_refresh_session_cookie_header(&state, &signed_session.refresh_token)?,
);
Ok((
headers,
json_success_body(
Some(&request_context),
PasswordEntryResponse {
token: access_token,
token: signed_session.access_token,
user: PasswordEntryUserPayload {
id: result.user.id,
username: result.user.username,