1use jsonwebtoken::{decode, DecodingKey, Validation};
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13
14#[derive(Debug, Serialize, Deserialize, Clone)]
19pub struct Claims {
20 #[serde(rename = "sub")]
22 pub login_id: String,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub exp: Option<i64>,
27
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub iat: Option<i64>,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub jti: Option<String>,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub iss: Option<String>,
39
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub aud: Option<String>,
43
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub login_type: Option<String>,
47
48 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
50 pub extra: HashMap<String, serde_json::Value>,
51}
52
53impl Claims {
54 pub fn user_id(&self) -> Option<i64> {
56 self.login_id.parse::<i64>().ok()
57 }
58
59 pub fn tenant_id(&self) -> Option<i64> {
61 self.extra
62 .get("tenant_id")
63 .and_then(|v| v.as_str())
64 .and_then(|s| s.parse::<i64>().ok())
65 }
66
67 pub fn username(&self) -> String {
69 self.extra
70 .get("username")
71 .and_then(|v| v.as_str())
72 .unwrap_or("")
73 .to_string()
74 }
75
76 pub fn token_type(&self) -> String {
78 self.extra
79 .get("token_type")
80 .and_then(|v| v.as_str())
81 .unwrap_or("access")
82 .to_string()
83 }
84}
85
86pub struct JwtService {
88 decoding_key: DecodingKey,
89}
90
91impl JwtService {
92 pub fn from_env() -> Result<Self, String> {
94 let secret = std::env::var("APP__JWT__SECRET")
95 .map_err(|_| "环境变量 APP__JWT__SECRET 未设置".to_string())?;
96
97 Ok(Self {
98 decoding_key: DecodingKey::from_secret(secret.as_bytes()),
99 })
100 }
101
102 pub fn new(secret: &str) -> Self {
104 Self {
105 decoding_key: DecodingKey::from_secret(secret.as_bytes()),
106 }
107 }
108
109 pub fn verify_token(&self, token: &str) -> Result<Claims, String> {
111 let token = token.trim();
112 let token = if token.starts_with("Bearer ") {
114 &token[7..]
115 } else {
116 token
117 };
118
119 let mut validation = Validation::default();
120 validation.leeway = 300; let token_data = decode::<Claims>(token, &self.decoding_key, &validation)
123 .map_err(|e| format!("JWT 验证失败: {}", e))?;
124
125 Ok(token_data.claims)
126 }
127}