br_crypto/
jwt.rs

1use chrono::Local;
2use json::{JsonValue, object};
3use crate::base64::{url_decode, url_encode};
4use crate::hmac::sha256;
5use crate::pkey::{pri_key_sign, pub_key_verify};
6
7#[derive(Clone)]
8pub struct Jwt {}
9
10impl Jwt {
11    /// 创建
12    ///
13    /// * alg 加密方式
14    /// * iss 签发人
15    /// * jti 签发TOKEN
16    /// * sub 主题
17    /// * aud 受众
18    /// * custom 自定义内容
19    /// * nbf 生效时间 秒s
20    /// * exp 过期时间 秒s
21    /// * key 加密密钥 rsa 为私钥匙
22    #[allow(clippy::too_many_arguments)]
23    pub fn create(alg: &str, iss: &str, jti: &str, sub: &str, aud: &str, custom: JsonValue, nbf: i64, exp: i64, key: &str) -> String {
24        let mut header = Header::default();
25        header.set_alg(alg);
26        let mut payload = Payload::new();
27        payload.iss = iss.to_string();
28        payload.jti = jti.to_string();
29        payload.sub = sub.to_string();
30        payload.aud = aud.to_string();
31        payload.custom = custom;
32        payload.set_nbf_exp(nbf, exp);
33
34        let signature = format!("{}.{}", header.clone().sign(), payload.clone().sign());
35        let data = match header.alg.clone() {
36            Alg::HS256 => sha256(key, signature.as_str()),
37            Alg::RSA => pri_key_sign(key, signature.as_str())
38        };
39        let sign = url_encode(data.to_string());
40        let token = format!("{signature}.{sign}");
41        token
42    }
43    /// 验证
44    /// * key rsa 为公匙
45    pub fn verify(token: &str, key: &str) -> Result<i64, String> {
46        let mut data: Vec<&str> = token.split(".").collect();
47        if data.len() != 3 {
48            return Err("TOKEN格式不正确".to_string());
49        }
50        let header = data.remove(0);
51        let payload = data.remove(0);
52        let signature = format!("{header}.{payload}");
53        let sign_old = data.remove(0);
54
55        let header = Header::from(header)?;
56        let sign_new = match header.alg {
57            Alg::HS256 => {
58                url_encode(sha256(key, signature.as_str()))
59            }
60            Alg::RSA => {
61                let sign = url_decode(sign_old.to_string());
62                if !pub_key_verify(key.to_string().clone(), signature.as_str(), sign) {
63                    return Err("签名不正确".to_string());
64                }
65                sign_old.to_string()
66            }
67        };
68        if sign_new != sign_old {
69            return Err("签名不一致".to_string());
70        }
71        let payload = Payload::from(payload)?;
72
73        let time = Local::now().timestamp();
74        // 生效时间早于当前时间
75        if payload.nbf > time {
76            return Err(format!("未生效: {}", payload.nbf - time));
77        }
78        // 过期时间小于当前时间
79        if time > payload.exp {
80            return Err(format!("已过期: {}", payload.exp));
81        }
82        Ok(payload.exp - time)
83    }
84    /// 信息
85    pub fn info(token: &str) -> Result<JsonValue, String> {
86        let mut data: Vec<&str> = token.split(".").collect();
87        if data.len() != 3 {
88            return Err("TOKEN格式不正确".to_string());
89        }
90        let header = data.remove(0);
91        let payload = data.remove(0);
92
93        let mut header = Header::from(header)?;
94        let mut payload = Payload::from(payload)?;
95        Ok(object! {
96            "header":header.json(),
97            "payload":payload.json()
98        })
99    }
100}
101
102#[derive(Clone)]
103pub enum Alg {
104    HS256,
105    RSA,
106}
107
108impl Alg {
109    pub fn str(&mut self) -> String {
110        match self {
111            Alg::HS256 => "HS256",
112            Alg::RSA => "RSA"
113        }.to_string()
114    }
115    pub fn from(name: &str) -> Self {
116        match name {
117            "HS256" => Alg::HS256,
118            "RSA" => Alg::RSA,
119            _ => Alg::HS256
120        }
121    }
122}
123
124#[derive(Clone)]
125pub struct Header {
126    /// 签名方式
127    alg: Alg,
128    /// 令牌类型
129    typ: String,
130}
131
132impl Header {
133    pub fn sign(&mut self) -> String {
134        let header = self.json();
135        url_encode(header.to_string())
136    }
137    pub fn set_alg(&mut self, alg: &str) {
138        if !alg.is_empty() {
139            self.alg = Alg::from(alg);
140        }
141    }
142    pub fn from(str: &str) -> Result<Header, String> {
143        let mut header = Header::default();
144        let header_text = url_decode(str.to_string());
145        header.alg = match json::parse(header_text.as_str()) {
146            Ok(e) => {
147                Alg::from(e["alg"].as_str().unwrap_or(""))
148            }
149            Err(e) => {
150                return Err(e.to_string());
151            }
152        };
153        Ok(header)
154    }
155    pub fn json(&mut self) -> JsonValue {
156        object! {
157            alg:self.alg.str(),
158            typ:self.typ.clone()
159        }
160    }
161}
162
163impl Default for Header {
164    fn default() -> Self {
165        Self {
166            alg: Alg::HS256,
167            typ: "JWT".to_string(),
168        }
169    }
170}
171/// 载荷
172#[derive(Clone)]
173pub struct Payload {
174    /// 签发人
175    pub iss: String,
176    /// 签发时间
177    pub iat: i64,
178    /// 签发TOKEN
179    pub jti: String,
180
181    /// 主题
182    pub sub: String,
183    /// 受众
184    pub aud: String,
185    /// 自定义内容
186    pub custom: JsonValue,
187
188    /// 生效时间 秒s
189    pub nbf: i64,
190    /// 过期时间 秒s
191    pub exp: i64,
192
193}
194impl Default for Payload {
195    fn default() -> Self {
196        Self::new()
197    }
198}
199
200impl Payload {
201    pub fn new() -> Self {
202        Self {
203            iss: "".to_string(),
204            iat: Local::now().timestamp(),
205            jti: "".to_string(),
206            sub: "".to_string(),
207            aud: "".to_string(),
208            custom: JsonValue::Null,
209            nbf: 0,
210            exp: 0,
211        }
212    }
213    pub fn sign(&mut self) -> String {
214        let payload = self.json();
215        url_encode(payload.to_string())
216    }
217    pub fn from(str: &str) -> Result<Payload, String> {
218        let payload_text = url_decode(str.to_string());
219        match json::parse(payload_text.as_str()) {
220            Ok(payload) => {
221                Ok(Self {
222                    iss: payload["iss"].to_string(),
223                    iat: payload["iat"].as_i64().unwrap_or(0),
224                    jti: payload["jti"].to_string(),
225                    sub: payload["sub"].to_string(),
226                    aud: payload["aud"].to_string(),
227                    custom: payload["custom"].clone(),
228                    nbf: payload["nbf"].as_i64().unwrap_or(0),
229                    exp: payload["exp"].as_i64().unwrap_or(0),
230                })
231            }
232            Err(_) => Err("载荷错误".to_string())
233        }
234    }
235    pub fn set_nbf_exp(&mut self, nbf: i64, exp: i64) {
236        if nbf == 0 {
237            self.nbf = Local::now().timestamp();
238        } else {
239            self.nbf = nbf;
240        }
241        self.exp = self.nbf + exp;
242    }
243    pub fn json(&mut self) -> JsonValue {
244        object! {
245            iss: self.iss.clone(),
246            iat:  self.iat,
247            jti:  self.jti.clone(),
248            sub: self.sub.clone(),
249            aud:  self.aud.clone(),
250            custom:  self.custom.clone(),
251            nbf: self.nbf,
252            exp:  self.exp
253        }
254    }
255}