后端重写提交

This commit is contained in:
2026-04-22 12:34:49 +08:00
parent cf8da3f50f
commit 997a8daada
438 changed files with 53355 additions and 865 deletions

View File

@@ -6,6 +6,7 @@ license.workspace = true
[dependencies]
platform-auth = { path = "../platform-auth" }
shared-kernel = { path = "../shared-kernel" }
time = { version = "0.3", features = ["formatting", "parsing"] }
uuid = { version = "1", features = ["v4"] }

View File

@@ -6,8 +6,11 @@ use std::{
};
use platform_auth::{hash_password, verify_password};
use shared_kernel::{
build_prefixed_uuid_id, format_rfc3339 as format_shared_rfc3339, new_uuid_simple_string,
normalize_optional_string, normalize_required_string, parse_rfc3339,
};
use time::{Duration, OffsetDateTime};
use uuid::Uuid;
const USERNAME_MIN_LENGTH: usize = 3;
const USERNAME_MAX_LENGTH: usize = 24;
@@ -463,22 +466,14 @@ impl RefreshSessionService {
.map_err(map_password_store_error)?
.ok_or(RefreshSessionError::UserNotFound)?;
let session_id = format!("usess_{}", Uuid::new_v4().simple());
let session_id = build_prefixed_uuid_id("usess_");
let expires_at = now
.checked_add(Duration::days(i64::from(self.refresh_session_ttl_days)))
.ok_or_else(|| {
RefreshSessionError::Store("refresh session 过期时间计算溢出".to_string())
})?;
let now_iso = now
.format(&time::format_description::well_known::Rfc3339)
.map_err(|error| {
RefreshSessionError::Store(format!("refresh session 时间格式化失败:{error}"))
})?;
let expires_at_iso = expires_at
.format(&time::format_description::well_known::Rfc3339)
.map_err(|error| {
RefreshSessionError::Store(format!("refresh session 过期时间格式化失败:{error}"))
})?;
let now_iso = format_rfc3339_with_context(now, "refresh session 时间")?;
let expires_at_iso = format_rfc3339_with_context(expires_at, "refresh session 过期时间")?;
let session = RefreshSessionRecord {
session_id,
user_id: input.user_id,
@@ -502,10 +497,9 @@ impl RefreshSessionService {
input: RotateRefreshSessionInput,
now: OffsetDateTime,
) -> Result<RotateRefreshSessionResult, RefreshSessionError> {
let refresh_token_hash = input.refresh_token_hash.trim().to_string();
if refresh_token_hash.is_empty() {
let Some(refresh_token_hash) = normalize_required_string(&input.refresh_token_hash) else {
return Err(RefreshSessionError::MissingToken);
}
};
let session = self
.store
@@ -516,13 +510,8 @@ impl RefreshSessionService {
return Err(RefreshSessionError::SessionNotFound);
}
let expires_at = OffsetDateTime::parse(
&session.session.expires_at,
&time::format_description::well_known::Rfc3339,
)
.map_err(|error| {
RefreshSessionError::Store(format!("refresh session 过期时间解析失败:{error}"))
})?;
let expires_at =
parse_rfc3339_with_context(&session.session.expires_at, "refresh session 过期时间")?;
if expires_at <= now {
return Err(RefreshSessionError::SessionExpired);
}
@@ -538,16 +527,9 @@ impl RefreshSessionService {
.ok_or_else(|| {
RefreshSessionError::Store("refresh session 过期时间计算溢出".to_string())
})?;
let now_iso = now
.format(&time::format_description::well_known::Rfc3339)
.map_err(|error| {
RefreshSessionError::Store(format!("refresh session 时间格式化失败:{error}"))
})?;
let next_expires_at_iso = next_expires_at
.format(&time::format_description::well_known::Rfc3339)
.map_err(|error| {
RefreshSessionError::Store(format!("refresh session 过期时间格式化失败:{error}"))
})?;
let now_iso = format_rfc3339_with_context(now, "refresh session 时间")?;
let next_expires_at_iso =
format_rfc3339_with_context(next_expires_at, "refresh session 过期时间")?;
let updated_session = self.store.rotate_session(
&session.session.session_id,
@@ -719,9 +701,9 @@ impl WechatAuthStateService {
WechatAuthError::Store(format!("微信 state 过期时间格式化失败:{message}"))
})?;
let state = WechatAuthStateRecord {
wechat_state_id: format!("wxstate_{}", Uuid::new_v4().simple()),
wechat_state_id: build_prefixed_uuid_id("wxstate_"),
state_token: create_wechat_state_token(),
redirect_path: input.redirect_path.trim().to_string(),
redirect_path: normalize_required_string(&input.redirect_path).unwrap_or_default(),
scene: input.scene,
request_user_agent: normalize_optional_string(input.request_user_agent),
expires_at,
@@ -1035,7 +1017,7 @@ impl InMemoryAuthStore {
);
let identity = StoredWechatIdentity {
user_id: user_id.clone(),
provider_uid: profile.provider_uid.trim().to_string(),
provider_uid: normalize_required_string(&profile.provider_uid).unwrap_or_default(),
provider_union_id: normalize_optional_string(profile.provider_union_id),
display_name: normalize_optional_string(profile.display_name),
avatar_url: normalize_optional_string(profile.avatar_url),
@@ -1100,7 +1082,8 @@ impl InMemoryAuthStore {
let next_display_name = normalize_optional_string(profile.display_name);
let next_avatar_url = normalize_optional_string(profile.avatar_url);
let next_provider_union_id = normalize_optional_string(profile.provider_union_id);
let next_provider_uid = profile.provider_uid.trim().to_string();
let next_provider_uid =
normalize_required_string(&profile.provider_uid).unwrap_or_default();
{
let identity = state
.wechat_identity_by_provider_uid
@@ -1717,7 +1700,7 @@ fn map_refresh_error_to_logout_error(error: RefreshSessionError) -> LogoutError
}
fn normalize_username(raw_username: &str) -> Result<String, PasswordEntryError> {
let username = raw_username.trim().to_string();
let username = normalize_required_string(raw_username).unwrap_or_default();
let valid_length =
(USERNAME_MIN_LENGTH..=USERNAME_MAX_LENGTH).contains(&username.chars().count());
let valid_chars = username
@@ -1775,21 +1758,11 @@ fn mask_phone_number(phone_number: &str) -> String {
format!("{}****{}", &phone_number[..3], &phone_number[7..11])
}
fn normalize_optional_string(value: Option<String>) -> Option<String> {
value.and_then(|field| {
let trimmed = field.trim().to_string();
if trimmed.is_empty() {
return None;
}
Some(trimmed)
})
}
fn build_random_password_seed() -> String {
format!(
"seed_{}_{}",
Uuid::new_v4().simple(),
Uuid::new_v4().simple()
new_uuid_simple_string(),
new_uuid_simple_string()
)
}
@@ -1798,13 +1771,11 @@ fn build_system_username(prefix: &str, sequence: u64) -> String {
}
fn format_rfc3339(value: OffsetDateTime) -> Result<String, String> {
value
.format(&time::format_description::well_known::Rfc3339)
.map_err(|error| error.to_string())
format_shared_rfc3339(value)
}
fn parse_phone_code_time(value: &str, field_label: &str) -> Result<OffsetDateTime, PhoneAuthError> {
OffsetDateTime::parse(value, &time::format_description::well_known::Rfc3339)
parse_rfc3339(value)
.map_err(|error| PhoneAuthError::Store(format!("短信验证码{field_label}解析失败:{error}")))
}
@@ -1818,7 +1789,23 @@ fn build_phone_code_key(phone_number: &str, scene: &PhoneAuthScene) -> String {
}
fn create_wechat_state_token() -> String {
Uuid::new_v4().simple().to_string()
new_uuid_simple_string()
}
fn format_rfc3339_with_context(
value: OffsetDateTime,
field_label: &str,
) -> Result<String, RefreshSessionError> {
format_shared_rfc3339(value)
.map_err(|error| RefreshSessionError::Store(format!("{field_label}格式化失败:{error}")))
}
fn parse_rfc3339_with_context(
value: &str,
field_label: &str,
) -> Result<OffsetDateTime, RefreshSessionError> {
parse_rfc3339(value)
.map_err(|error| RefreshSessionError::Store(format!("{field_label}解析失败:{error}")))
}
impl PhoneAuthScene {