sa_token_core/token/
jwt.rs

1// Author: 金书记
2//
3//! JWT (JSON Web Token) Module | JWT (JSON Web Token) 模块
4//!
5//! Provides complete JWT functionality including generation, validation, and parsing.
6//! 提供完整的 JWT 功能,包括生成、验证和解析。
7//!
8//! ## Features | 功能特性
9//!
10//! - Multiple algorithms support (HS256, HS384, HS512, RS256, etc.)
11//!   支持多种算法(HS256, HS384, HS512, RS256 等)
12//! - Custom claims support | 支持自定义声明
13//! - Expiration time validation | 过期时间验证
14//! - Token refresh | Token 刷新
15//!
16//! ## Usage Example | 使用示例
17//!
18//! ```rust,ignore
19//! use sa_token_core::token::jwt::{JwtManager, JwtClaims};
20//!
21//! // Create JWT manager | 创建 JWT 管理器
22//! let jwt_manager = JwtManager::new("your-secret-key");
23//!
24//! // Generate JWT token | 生成 JWT token
25//! let mut claims = JwtClaims::new("user_123");
26//! claims.set_expiration(3600); // 1 hour | 1小时
27//! let token = jwt_manager.generate(&claims)?;
28//!
29//! // Validate and parse JWT token | 验证并解析 JWT token
30//! let decoded_claims = jwt_manager.validate(&token)?;
31//! println!("User ID: {}", decoded_claims.login_id);
32//! ```
33
34use chrono::{DateTime, Duration, Utc};
35use jsonwebtoken::{
36    decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation,
37};
38use serde::{Deserialize, Serialize};
39use serde_json::Value;
40use std::collections::HashMap;
41
42use crate::error::{SaTokenError, SaTokenResult};
43
44/// JWT Algorithm | JWT 算法
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
46pub enum JwtAlgorithm {
47    /// HMAC using SHA-256 | 使用 SHA-256 的 HMAC
48    HS256,
49    /// HMAC using SHA-384 | 使用 SHA-384 的 HMAC
50    HS384,
51    /// HMAC using SHA-512 | 使用 SHA-512 的 HMAC
52    HS512,
53    /// RSA using SHA-256 | 使用 SHA-256 的 RSA
54    RS256,
55    /// RSA using SHA-384 | 使用 SHA-384 的 RSA
56    RS384,
57    /// RSA using SHA-512 | 使用 SHA-512 的 RSA
58    RS512,
59    /// ECDSA using SHA-256 | 使用 SHA-256 的 ECDSA
60    ES256,
61    /// ECDSA using SHA-384 | 使用 SHA-384 的 ECDSA
62    ES384,
63}
64
65impl Default for JwtAlgorithm {
66    fn default() -> Self {
67        Self::HS256
68    }
69}
70
71impl From<JwtAlgorithm> for Algorithm {
72    fn from(alg: JwtAlgorithm) -> Self {
73        match alg {
74            JwtAlgorithm::HS256 => Algorithm::HS256,
75            JwtAlgorithm::HS384 => Algorithm::HS384,
76            JwtAlgorithm::HS512 => Algorithm::HS512,
77            JwtAlgorithm::RS256 => Algorithm::RS256,
78            JwtAlgorithm::RS384 => Algorithm::RS384,
79            JwtAlgorithm::RS512 => Algorithm::RS512,
80            JwtAlgorithm::ES256 => Algorithm::ES256,
81            JwtAlgorithm::ES384 => Algorithm::ES384,
82        }
83    }
84}
85
86/// JWT Claims | JWT 声明
87///
88/// Standard JWT claims with sa-token extensions
89/// 标准 JWT 声明及 sa-token 扩展
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct JwtClaims {
92    /// Subject (user identifier) | 主题(用户标识符)
93    #[serde(rename = "sub")]
94    pub login_id: String,
95
96    /// Issuer | 签发者
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub iss: Option<String>,
99
100    /// Audience | 受众
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub aud: Option<String>,
103
104    /// Expiration time (Unix timestamp) | 过期时间(Unix 时间戳)
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub exp: Option<i64>,
107
108    /// Not before time (Unix timestamp) | 生效时间(Unix 时间戳)
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub nbf: Option<i64>,
111
112    /// Issued at time (Unix timestamp) | 签发时间(Unix 时间戳)
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub iat: Option<i64>,
115
116    /// JWT ID (unique identifier) | JWT ID(唯一标识符)
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub jti: Option<String>,
119
120    // Sa-token extensions | Sa-token 扩展字段
121
122    /// Login type (user, admin, etc.) | 登录类型(用户、管理员等)
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub login_type: Option<String>,
125
126    /// Device identifier | 设备标识
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub device: Option<String>,
129
130    /// Custom data | 自定义数据
131    #[serde(flatten)]
132    pub extra: HashMap<String, Value>,
133}
134
135impl JwtClaims {
136    /// Create new JWT claims | 创建新的 JWT 声明
137    ///
138    /// # Arguments | 参数
139    ///
140    /// * `login_id` - User identifier | 用户标识符
141    pub fn new(login_id: impl Into<String>) -> Self {
142        let now = Utc::now().timestamp();
143        Self {
144            login_id: login_id.into(),
145            iss: None,
146            aud: None,
147            exp: None,
148            nbf: None,
149            iat: Some(now),
150            jti: None,
151            login_type: Some("default".to_string()),
152            device: None,
153            extra: HashMap::new(),
154        }
155    }
156
157    /// Set expiration time in seconds from now | 设置从现在开始的过期时间(秒)
158    ///
159    /// # Arguments | 参数
160    ///
161    /// * `seconds` - Seconds until expiration | 到期秒数
162    pub fn set_expiration(&mut self, seconds: i64) -> &mut Self {
163        let exp_time = Utc::now() + Duration::seconds(seconds);
164        self.exp = Some(exp_time.timestamp());
165        self
166    }
167
168    /// Set expiration at specific time | 设置具体的过期时间
169    pub fn set_expiration_at(&mut self, datetime: DateTime<Utc>) -> &mut Self {
170        self.exp = Some(datetime.timestamp());
171        self
172    }
173
174    /// Set issuer | 设置签发者
175    pub fn set_issuer(&mut self, issuer: impl Into<String>) -> &mut Self {
176        self.iss = Some(issuer.into());
177        self
178    }
179
180    /// Set audience | 设置受众
181    pub fn set_audience(&mut self, audience: impl Into<String>) -> &mut Self {
182        self.aud = Some(audience.into());
183        self
184    }
185
186    /// Set JWT ID | 设置 JWT ID
187    pub fn set_jti(&mut self, jti: impl Into<String>) -> &mut Self {
188        self.jti = Some(jti.into());
189        self
190    }
191
192    /// Set login type | 设置登录类型
193    pub fn set_login_type(&mut self, login_type: impl Into<String>) -> &mut Self {
194        self.login_type = Some(login_type.into());
195        self
196    }
197
198    /// Set device identifier | 设置设备标识
199    pub fn set_device(&mut self, device: impl Into<String>) -> &mut Self {
200        self.device = Some(device.into());
201        self
202    }
203
204    /// Add custom claim | 添加自定义声明
205    pub fn add_claim(&mut self, key: impl Into<String>, value: Value) -> &mut Self {
206        self.extra.insert(key.into(), value);
207        self
208    }
209
210    /// Get custom claim | 获取自定义声明
211    pub fn get_claim(&self, key: &str) -> Option<&Value> {
212        self.extra.get(key)
213    }
214
215    /// Check if token is expired | 检查 token 是否过期
216    pub fn is_expired(&self) -> bool {
217        if let Some(exp) = self.exp {
218            let now = Utc::now().timestamp();
219            now >= exp
220        } else {
221            false
222        }
223    }
224
225    /// Get remaining time in seconds | 获取剩余时间(秒)
226    pub fn remaining_time(&self) -> Option<i64> {
227        self.exp.map(|exp| {
228            let now = Utc::now().timestamp();
229            (exp - now).max(0)
230        })
231    }
232}
233
234/// JWT Manager | JWT 管理器
235///
236/// Manages JWT token generation, validation, and parsing
237/// 管理 JWT token 的生成、验证和解析
238#[derive(Clone)]
239pub struct JwtManager {
240    /// Secret key for HMAC algorithms | HMAC 算法的密钥
241    secret: String,
242
243    /// Algorithm to use | 使用的算法
244    algorithm: JwtAlgorithm,
245
246    /// Issuer | 签发者
247    issuer: Option<String>,
248
249    /// Audience | 受众
250    audience: Option<String>,
251}
252
253impl JwtManager {
254    /// Create new JWT manager with HS256 algorithm | 创建使用 HS256 算法的新 JWT 管理器
255    ///
256    /// # Arguments | 参数
257    ///
258    /// * `secret` - Secret key | 密钥
259    pub fn new(secret: impl Into<String>) -> Self {
260        Self {
261            secret: secret.into(),
262            algorithm: JwtAlgorithm::HS256,
263            issuer: None,
264            audience: None,
265        }
266    }
267
268    /// Create JWT manager with custom algorithm | 创建使用自定义算法的 JWT 管理器
269    pub fn with_algorithm(secret: impl Into<String>, algorithm: JwtAlgorithm) -> Self {
270        Self {
271            secret: secret.into(),
272            algorithm,
273            issuer: None,
274            audience: None,
275        }
276    }
277
278    /// Set issuer | 设置签发者
279    pub fn set_issuer(mut self, issuer: impl Into<String>) -> Self {
280        self.issuer = Some(issuer.into());
281        self
282    }
283
284    /// Set audience | 设置受众
285    pub fn set_audience(mut self, audience: impl Into<String>) -> Self {
286        self.audience = Some(audience.into());
287        self
288    }
289
290    /// Generate JWT token | 生成 JWT token
291    ///
292    /// # Arguments | 参数
293    ///
294    /// * `claims` - JWT claims | JWT 声明
295    ///
296    /// # Returns | 返回
297    ///
298    /// JWT token string | JWT token 字符串
299    pub fn generate(&self, claims: &JwtClaims) -> SaTokenResult<String> {
300        let mut final_claims = claims.clone();
301
302        // Set issuer and audience if configured
303        // 如果配置了签发者和受众,则设置
304        if self.issuer.is_some() && final_claims.iss.is_none() {
305            final_claims.iss = self.issuer.clone();
306        }
307        if self.audience.is_some() && final_claims.aud.is_none() {
308            final_claims.aud = self.audience.clone();
309        }
310
311        let header = Header::new(self.algorithm.into());
312        let encoding_key = EncodingKey::from_secret(self.secret.as_bytes());
313
314        encode(&header, &final_claims, &encoding_key).map_err(|e| {
315            SaTokenError::InvalidToken(format!("Failed to generate JWT: {}", e))
316        })
317    }
318
319    /// Validate and parse JWT token | 验证并解析 JWT token
320    ///
321    /// # Arguments | 参数
322    ///
323    /// * `token` - JWT token string | JWT token 字符串
324    ///
325    /// # Returns | 返回
326    ///
327    /// Decoded JWT claims | 解码的 JWT 声明
328    pub fn validate(&self, token: &str) -> SaTokenResult<JwtClaims> {
329        let mut validation = Validation::new(self.algorithm.into());
330
331        // Explicitly enable expiration validation | 明确启用过期验证
332        validation.validate_exp = true;
333        
334        // Set leeway to 0 for strict validation | 设置时间偏差为0以进行严格验证
335        validation.leeway = 0;
336
337        // Configure validation | 配置验证
338        if let Some(ref iss) = self.issuer {
339            validation.set_issuer(&[iss]);
340        }
341        if let Some(ref aud) = self.audience {
342            validation.set_audience(&[aud]);
343        }
344
345        let decoding_key = DecodingKey::from_secret(self.secret.as_bytes());
346
347        let token_data = decode::<JwtClaims>(token, &decoding_key, &validation).map_err(|e| {
348            match e.kind() {
349                jsonwebtoken::errors::ErrorKind::ExpiredSignature => {
350                    SaTokenError::TokenExpired
351                }
352                _ => SaTokenError::InvalidToken(format!("JWT validation failed: {}", e)),
353            }
354        })?;
355
356        Ok(token_data.claims)
357    }
358
359    /// Decode JWT without validation (unsafe) | 不验证解码 JWT(不安全)
360    ///
361    /// Warning: This does not validate the signature!
362    /// 警告:这不会验证签名!
363    pub fn decode_without_validation(&self, token: &str) -> SaTokenResult<JwtClaims> {
364        let mut validation = Validation::new(self.algorithm.into());
365        validation.insecure_disable_signature_validation();
366        validation.validate_exp = false;
367
368        let decoding_key = DecodingKey::from_secret(self.secret.as_bytes());
369
370        let token_data = decode::<JwtClaims>(token, &decoding_key, &validation).map_err(|e| {
371            SaTokenError::InvalidToken(format!("Failed to decode JWT: {}", e))
372        })?;
373
374        Ok(token_data.claims)
375    }
376
377    /// Refresh JWT token | 刷新 JWT token
378    ///
379    /// Creates a new token with updated expiration time
380    /// 创建具有更新过期时间的新 token
381    ///
382    /// # Arguments | 参数
383    ///
384    /// * `token` - Original JWT token | 原始 JWT token
385    /// * `extend_seconds` - Seconds to extend | 延长的秒数
386    pub fn refresh(&self, token: &str, extend_seconds: i64) -> SaTokenResult<String> {
387        let mut claims = self.validate(token)?;
388
389        // Update expiration time | 更新过期时间
390        claims.set_expiration(extend_seconds);
391
392        // Update issued at time | 更新签发时间
393        claims.iat = Some(Utc::now().timestamp());
394
395        self.generate(&claims)
396    }
397
398    /// Extract user ID from token without full validation | 从 token 提取用户 ID(无需完整验证)
399    ///
400    /// Useful for quick user identification
401    /// 用于快速用户识别
402    pub fn extract_login_id(&self, token: &str) -> SaTokenResult<String> {
403        let claims = self.decode_without_validation(token)?;
404        Ok(claims.login_id)
405    }
406}
407
408#[cfg(test)]
409mod tests {
410    use super::*;
411
412    #[test]
413    fn test_jwt_claims_creation() {
414        let mut claims = JwtClaims::new("user_123");
415        claims.set_expiration(3600);
416        claims.set_issuer("sa-token");
417        claims.add_claim("role", serde_json::json!("admin"));
418
419        assert_eq!(claims.login_id, "user_123");
420        assert!(claims.exp.is_some());
421        assert_eq!(claims.iss, Some("sa-token".to_string()));
422        assert_eq!(
423            claims.get_claim("role"),
424            Some(&serde_json::json!("admin"))
425        );
426    }
427
428    #[test]
429    fn test_jwt_generate_and_validate() {
430        let jwt_manager = JwtManager::new("test-secret-key");
431
432        let mut claims = JwtClaims::new("user_123");
433        claims.set_expiration(3600);
434
435        // Generate token | 生成 token
436        let token = jwt_manager.generate(&claims).unwrap();
437        assert!(!token.is_empty());
438
439        // Validate token | 验证 token
440        let decoded = jwt_manager.validate(&token).unwrap();
441        assert_eq!(decoded.login_id, "user_123");
442        assert!(!decoded.is_expired());
443    }
444
445    #[test]
446    fn test_jwt_expired() {
447        let jwt_manager = JwtManager::new("test-secret-key");
448
449        let mut claims = JwtClaims::new("user_123");
450        // Set expiration to 10 seconds in the past to account for leeway
451        // 设置过期时间为10秒前以考虑时间偏差
452        let exp_time = Utc::now() - Duration::seconds(10);
453        claims.set_expiration_at(exp_time);
454
455        let token = jwt_manager.generate(&claims).unwrap();
456
457        // Should fail validation due to expiration | 应该因过期而验证失败
458        let result = jwt_manager.validate(&token);
459        assert!(result.is_err());
460        
461        // Verify it's specifically an expiration error | 验证是过期错误
462        match result {
463            Err(SaTokenError::TokenExpired) => {}, // Expected | 预期
464            _ => panic!("Expected TokenExpired error"),
465        }
466    }
467
468    #[test]
469    fn test_jwt_refresh() {
470        let jwt_manager = JwtManager::new("test-secret-key");
471
472        let mut claims = JwtClaims::new("user_123");
473        claims.set_expiration(3600);
474
475        let original_token = jwt_manager.generate(&claims).unwrap();
476
477        // Refresh token | 刷新 token
478        let new_token = jwt_manager.refresh(&original_token, 7200).unwrap();
479        assert_ne!(original_token, new_token);
480
481        // Validate new token | 验证新 token
482        let decoded = jwt_manager.validate(&new_token).unwrap();
483        assert_eq!(decoded.login_id, "user_123");
484    }
485
486    #[test]
487    fn test_jwt_custom_claims() {
488        let jwt_manager = JwtManager::new("test-secret-key");
489
490        let mut claims = JwtClaims::new("user_123");
491        claims.set_expiration(3600);
492        claims.add_claim("role", serde_json::json!("admin"));
493        claims.add_claim("permissions", serde_json::json!(["read", "write"]));
494
495        let token = jwt_manager.generate(&claims).unwrap();
496        let decoded = jwt_manager.validate(&token).unwrap();
497
498        assert_eq!(decoded.get_claim("role"), Some(&serde_json::json!("admin")));
499        assert_eq!(
500            decoded.get_claim("permissions"),
501            Some(&serde_json::json!(["read", "write"]))
502        );
503    }
504
505    #[test]
506    fn test_extract_login_id() {
507        let jwt_manager = JwtManager::new("test-secret-key");
508
509        let mut claims = JwtClaims::new("user_123");
510        claims.set_expiration(3600);
511
512        let token = jwt_manager.generate(&claims).unwrap();
513        let login_id = jwt_manager.extract_login_id(&token).unwrap();
514
515        assert_eq!(login_id, "user_123");
516    }
517}
518