df_crypto/
jwt.rs

1use chrono::Local;
2use json::{JsonValue, object};
3use log::info;
4use crate::base64::{url_decode, url_encode};
5use crate::hmac::str_to_hmacsha256;
6
7pub struct Jwt {
8    header: JsonValue,
9    payload: JsonValue,
10}
11
12impl Jwt {
13    /// 初始化
14    ///
15    /// * iss 签发人
16    pub fn default(iss: &str) -> Self {
17        Self {
18            header: object! {
19                "alg":"HS256",
20                "typ": "JWT"
21            },
22            payload: object! {
23                "iss":iss.clone(),
24                "iat":Local::now().timestamp(),
25                "jti":uuid::Uuid::new_v4().to_string()
26            },
27        }
28    }
29    /// token信息
30    ///
31    /// * sub 主题
32    /// * aud 受众
33    /// * custom 自定义内容
34    pub fn payload(&mut self, sub: &str, aud: &str, custom: JsonValue) -> &mut Self {
35        self.payload["sub"] = sub.into();
36        self.payload["aud"] = aud.into();
37        self.payload["custom"] = custom.into();
38        self
39    }
40    /// 生效时间与过期时间设置
41    ///
42    /// * nbf 生效时间
43    /// * exp 过期时间 分钟
44    pub fn nbf_exp(&mut self, nbf: i64, exp: i64) -> &mut Self {
45        if nbf == 0 {
46            self.payload["nbf"] = (Local::now().timestamp()).into();
47        } else {
48            self.payload["nbf"] = nbf.into();
49        }
50        let nbf = self.payload["nbf"].as_i64().unwrap();
51        let exp = 60 * exp * 1000;
52        self.payload["exp"] = (nbf + exp).into();
53        self
54    }
55    /// 返回口令
56    ///
57    /// * key 加密密钥
58    pub fn sign(&mut self, key: &str) -> String {
59        let header = url_encode(self.header.to_string());
60        let payload = url_encode(self.payload.to_string());
61        let signature = format!("{}.{}", header, payload);
62        let data = str_to_hmacsha256(key.clone(), signature.as_str().clone());
63        let sign = url_encode(data.to_string());
64        let token = format!("{}.{}.{}", header, payload, sign);
65        return token;
66    }
67    /// 验证
68    pub fn verify(token: &str, key: &str) -> bool {
69        let binding = token.to_string();
70        let data: Vec<&str> = binding.split(".").collect();
71        if data.len() < 3 {
72            return false;
73        }
74        let header = data[0].clone();
75        let payload = data[1].clone();
76        let signature = format!("{}.{}", header, payload);
77        let sign_old = data[2].clone();
78
79        let header = url_decode(header.to_string());
80        let header = json::parse(header.as_str()).unwrap();
81        let alg = header["alg"].as_str().unwrap();
82        let sign_new = {
83            match alg {
84                "HS256" => {
85                    let hmacsha256 = str_to_hmacsha256(key.clone(), signature.as_str().clone());
86                    url_encode(hmacsha256)
87                }
88                _ => {
89                    signature
90                }
91            }
92        };
93        if sign_new != sign_old {
94            return false;
95        }
96        let payload_text = url_decode(payload.to_string());
97        match json::parse(payload_text.as_str()) {
98            Ok(payload) => {
99                let time = Local::now().timestamp();
100                // 生效时间早于当前时间
101                let nbf = payload["nbf"].as_i64().unwrap();
102                if nbf > time {
103                    return false;
104                }
105                // 过期时间小于当前时间
106                let exp = payload["exp"].as_i64().unwrap();
107                if time > exp {
108                    return false;
109                }
110                return true;
111            }
112            Err(e) => {
113                info!("{}",e);
114                info!("payload_old:{}",payload);
115                info!("payload_new:{}",payload_text);
116                return false;
117            }
118        }
119    }
120    /// 信息
121    pub fn info(token: &str) -> JsonValue {
122        let binding = token.to_string();
123        let data: Vec<&str> = binding.split(".").collect();
124        let header = data[0].clone();
125        let payload = data[1].clone();
126        let header = url_decode(header.to_string());
127        let header = {
128            let res = json::parse(header.as_str());
129            match res {
130                Ok(e) => e,
131                Err(_) => object! {}
132            }
133        };
134        let payload = url_decode(payload.to_string());
135        let payload = {
136            let res = json::parse(payload.as_str());
137            match res {
138                Ok(e) => e,
139                Err(_) => object! {}
140            }
141        };
142        return object! {
143            "header":header,
144            "payload":payload
145        };
146    }
147}