sa_token_core/
error.rs

1// Author: 金书记
2//
3//! Error type definitions | 错误类型定义
4
5use thiserror::Error;
6
7pub type SaTokenResult<T> = Result<T, SaTokenError>;
8
9#[derive(Debug, Error)]
10pub enum SaTokenError {
11    // ============ Basic Token Errors | 基础 Token 错误 ============
12    #[error("Token not found or expired")]
13    TokenNotFound,
14    
15    #[error("Token is invalid: {0}")]
16    InvalidToken(String),
17    
18    #[error("Token has expired")]
19    TokenExpired,
20    
21    // ============ Authentication Errors | 认证错误 ============
22    #[error("User not logged in")]
23    NotLogin,
24    
25    #[error("Token is inactive")]
26    TokenInactive,
27    
28    // ============ Authorization Errors | 授权错误 ============
29    #[error("Permission denied")]
30    PermissionDenied,
31    
32    #[error("Permission denied: missing permission '{0}'")]
33    PermissionDeniedDetail(String),
34    
35    #[error("Role denied: missing role '{0}'")]
36    RoleDenied(String),
37    
38    // ============ Account Status Errors | 账户状态错误 ============
39    #[error("Account is banned until {0}")]
40    AccountBanned(String),
41    
42    #[error("Account is kicked out")]
43    AccountKickedOut,
44    
45    // ============ Session Errors | Session 错误 ============
46    #[error("Session not found")]
47    SessionNotFound,
48    
49    // ============ Nonce Errors | Nonce 错误 ============
50    #[error("Nonce has been used, possible replay attack detected")]
51    NonceAlreadyUsed,
52    
53    #[error("Invalid nonce format")]
54    InvalidNonceFormat,
55    
56    #[error("Nonce timestamp is invalid or expired")]
57    InvalidNonceTimestamp,
58    
59    // ============ Refresh Token Errors | 刷新令牌错误 ============
60    #[error("Refresh token not found or expired")]
61    RefreshTokenNotFound,
62    
63    #[error("Invalid refresh token data")]
64    RefreshTokenInvalidData,
65    
66    #[error("Missing login_id in refresh token")]
67    RefreshTokenMissingLoginId,
68    
69    #[error("Invalid expire time format in refresh token")]
70    RefreshTokenInvalidExpireTime,
71    
72    // ============ Token Validation Errors | Token 验证错误 ============
73    #[error("Token is empty")]
74    TokenEmpty,
75    
76    #[error("Token is too short")]
77    TokenTooShort,
78    
79    #[error("Login ID is not a valid number")]
80    LoginIdNotNumber,
81    
82    // ============ OAuth2 Errors | OAuth2 错误 ============
83    #[error("OAuth2 client not found")]
84    OAuth2ClientNotFound,
85    
86    #[error("Invalid client credentials")]
87    OAuth2InvalidCredentials,
88    
89    #[error("Client ID mismatch")]
90    OAuth2ClientIdMismatch,
91    
92    #[error("Redirect URI mismatch")]
93    OAuth2RedirectUriMismatch,
94    
95    #[error("Authorization code not found or expired")]
96    OAuth2CodeNotFound,
97    
98    #[error("Access token not found or expired")]
99    OAuth2AccessTokenNotFound,
100    
101    #[error("Refresh token not found or expired")]
102    OAuth2RefreshTokenNotFound,
103    
104    #[error("Invalid refresh token data")]
105    OAuth2InvalidRefreshToken,
106    
107    #[error("Invalid scope data")]
108    OAuth2InvalidScope,
109    
110    // ============ SSO Errors | SSO 单点登录错误 ============
111    #[error("SSO ticket not found or invalid")]
112    InvalidTicket,
113    
114    #[error("SSO ticket has expired")]
115    TicketExpired,
116    
117    #[error("Service URL mismatch")]
118    ServiceMismatch,
119    
120    #[error("SSO session not found")]
121    SsoSessionNotFound,
122    
123    // ============ System Errors | 系统错误 ============
124    #[error("Storage error: {0}")]
125    StorageError(String),
126    
127    #[error("Configuration error: {0}")]
128    ConfigError(String),
129    
130    #[error("Serialization error: {0}")]
131    SerializationError(#[from] serde_json::Error),
132    
133    #[error("Internal error: {0}")]
134    InternalError(String),
135}
136
137impl SaTokenError {
138    /// Get the error message as a string
139    /// 
140    /// This method returns the English error message for the error.
141    /// The error messages are defined using the `#[error(...)]` attribute.
142    /// 
143    /// # Examples
144    /// 
145    /// ```rust,ignore
146    /// let err = SaTokenError::NotLogin;
147    /// assert_eq!(err.message(), "User not logged in");
148    /// ```
149    pub fn message(&self) -> String {
150        self.to_string()
151    }
152    
153    /// Check if the error is an authentication error
154    /// 
155    /// Returns `true` for errors related to authentication (login/token validity)
156    pub fn is_auth_error(&self) -> bool {
157        matches!(
158            self,
159            Self::NotLogin 
160            | Self::TokenNotFound 
161            | Self::TokenExpired 
162            | Self::TokenInactive 
163            | Self::InvalidToken(_)
164        )
165    }
166    
167    /// Check if the error is an authorization error
168    /// 
169    /// Returns `true` for errors related to permissions or roles
170    pub fn is_authz_error(&self) -> bool {
171        matches!(
172            self,
173            Self::PermissionDenied 
174            | Self::PermissionDeniedDetail(_) 
175            | Self::RoleDenied(_)
176        )
177    }
178}
179
180/// Application-level error messages
181/// 
182/// These constants provide standard error messages for application-specific errors
183/// that are not part of SaTokenError.
184/// 
185/// # Examples
186/// 
187/// ```rust,ignore
188/// use sa_token_core::error::messages;
189/// 
190/// let err_msg = messages::INVALID_CREDENTIALS;
191/// return Err(ApiError::Unauthorized(err_msg.to_string()));
192/// ```
193pub mod messages {
194    /// Invalid username or password
195    pub const INVALID_CREDENTIALS: &str = "Invalid username or password";
196    
197    /// Login failed
198    pub const LOGIN_FAILED: &str = "Login failed";
199    
200    /// Authentication error
201    pub const AUTH_ERROR: &str = "Authentication error";
202    
203    /// Permission required
204    pub const PERMISSION_REQUIRED: &str = "Permission required";
205    
206    /// Role required
207    pub const ROLE_REQUIRED: &str = "Role required";
208}