//! 认证领域错误。 //! //! 领域错误保持可测试、可映射,不能直接依赖 Axum、cookie 或平台 provider 错误模型。 use std::{error::Error, fmt}; #[derive(Clone, Debug, PartialEq, Eq)] pub enum PasswordEntryError { InvalidPhoneNumber, InvalidPasswordLength, InvalidDisplayName, InvalidAvatarDataUrl, EmptyProfileUpdate, InvalidPublicUserCode, InvalidCredentials, UserNotFound, Store(String), PasswordHash(String), } #[derive(Clone, Debug, PartialEq, Eq)] pub enum PhoneAuthError { InvalidPhoneNumber, InvalidVerifyCode, VerifyCodeNotFound, VerifyCodeExpired, SendCoolingDown { retry_after_seconds: u64 }, VerifyAttemptsExceeded, UserNotFound, UserStateMismatch, Store(String), PasswordHash(String), } #[derive(Clone, Debug, PartialEq, Eq)] pub enum WechatAuthError { MissingProfile, StateNotFound, StateExpired, StateConsumed, UserNotFound, MissingWechatIdentity, Store(String), PasswordHash(String), } #[derive(Clone, Debug, PartialEq, Eq)] pub enum RefreshSessionError { MissingToken, SessionNotFound, SessionExpired, UserNotFound, Store(String), } #[derive(Clone, Debug, PartialEq, Eq)] pub enum LogoutError { UserNotFound, Store(String), } impl fmt::Display for PasswordEntryError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::InvalidPhoneNumber => f.write_str("手机号格式不正确"), Self::InvalidPasswordLength => f.write_str("密码长度需要在 6 到 128 位之间"), Self::InvalidDisplayName => f.write_str("昵称格式不正确"), Self::InvalidAvatarDataUrl => f.write_str("头像图片格式不正确"), Self::EmptyProfileUpdate => f.write_str("请至少修改昵称或头像"), Self::InvalidPublicUserCode => f.write_str("百梦号格式不正确"), Self::InvalidCredentials => f.write_str("手机号或密码错误"), Self::UserNotFound => f.write_str("用户不存在"), Self::Store(message) | Self::PasswordHash(message) => f.write_str(message), } } } impl Error for PasswordEntryError {} impl fmt::Display for PhoneAuthError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::InvalidPhoneNumber => f.write_str("手机号格式不正确"), Self::InvalidVerifyCode => f.write_str("验证码错误"), Self::VerifyCodeNotFound => f.write_str("验证码不存在或已失效"), Self::VerifyCodeExpired => f.write_str("验证码已过期"), Self::SendCoolingDown { .. } => f.write_str("验证码发送过于频繁,请稍后再试"), Self::VerifyAttemptsExceeded => f.write_str("验证码错误次数过多,请重新获取验证码"), Self::UserNotFound => f.write_str("用户不存在"), Self::UserStateMismatch => f.write_str("当前账号状态不允许执行该操作"), Self::Store(message) | Self::PasswordHash(message) => f.write_str(message), } } } impl Error for PhoneAuthError {} impl fmt::Display for WechatAuthError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::MissingProfile => f.write_str("缺少微信身份信息"), Self::StateNotFound => f.write_str("微信登录状态已失效,请重新发起登录"), Self::StateExpired => f.write_str("微信登录状态已过期,请重新发起登录"), Self::StateConsumed => f.write_str("微信登录状态已被消费,请重新发起登录"), Self::UserNotFound => f.write_str("用户不存在"), Self::MissingWechatIdentity => f.write_str("当前账号缺少微信身份"), Self::Store(message) | Self::PasswordHash(message) => f.write_str(message), } } } impl Error for WechatAuthError {} impl fmt::Display for RefreshSessionError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::MissingToken => f.write_str("缺少刷新会话"), Self::SessionNotFound | Self::SessionExpired | Self::UserNotFound => { f.write_str("当前登录态已失效,请重新登录") } Self::Store(message) => f.write_str(message), } } } impl Error for RefreshSessionError {} impl fmt::Display for LogoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::UserNotFound => f.write_str("当前登录态已失效,请重新登录"), Self::Store(message) => f.write_str(message), } } } impl Error for LogoutError {} pub(crate) fn map_password_store_error(error: PasswordEntryError) -> RefreshSessionError { match error { PasswordEntryError::Store(message) => RefreshSessionError::Store(message), PasswordEntryError::InvalidPhoneNumber | PasswordEntryError::InvalidPasswordLength | PasswordEntryError::InvalidDisplayName | PasswordEntryError::InvalidAvatarDataUrl | PasswordEntryError::EmptyProfileUpdate | PasswordEntryError::InvalidPublicUserCode | PasswordEntryError::InvalidCredentials | PasswordEntryError::UserNotFound | PasswordEntryError::PasswordHash(_) => { RefreshSessionError::Store("用户仓储读取失败".to_string()) } } } pub(crate) fn map_password_error_to_phone_error(error: PasswordEntryError) -> PhoneAuthError { match error { PasswordEntryError::Store(message) => PhoneAuthError::Store(message), PasswordEntryError::PasswordHash(message) => PhoneAuthError::PasswordHash(message), PasswordEntryError::InvalidPhoneNumber | PasswordEntryError::InvalidPasswordLength | PasswordEntryError::InvalidDisplayName | PasswordEntryError::InvalidAvatarDataUrl | PasswordEntryError::EmptyProfileUpdate | PasswordEntryError::InvalidPublicUserCode | PasswordEntryError::InvalidCredentials | PasswordEntryError::UserNotFound => PhoneAuthError::Store("用户仓储读取失败".to_string()), } } pub(crate) fn map_password_error_to_logout_error(error: PasswordEntryError) -> LogoutError { match error { PasswordEntryError::Store(message) => LogoutError::Store(message), PasswordEntryError::InvalidPhoneNumber | PasswordEntryError::InvalidPasswordLength | PasswordEntryError::InvalidDisplayName | PasswordEntryError::InvalidAvatarDataUrl | PasswordEntryError::EmptyProfileUpdate | PasswordEntryError::InvalidPublicUserCode | PasswordEntryError::InvalidCredentials | PasswordEntryError::UserNotFound | PasswordEntryError::PasswordHash(_) => LogoutError::Store("用户仓储读取失败".to_string()), } } pub(crate) fn map_refresh_error_to_logout_error(error: RefreshSessionError) -> LogoutError { match error { RefreshSessionError::Store(message) => LogoutError::Store(message), RefreshSessionError::MissingToken | RefreshSessionError::SessionNotFound | RefreshSessionError::SessionExpired | RefreshSessionError::UserNotFound => LogoutError::Store("会话吊销失败".to_string()), } }