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 #[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 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 if payload.nbf > time {
76 return Err(format!("未生效: {}", payload.nbf - time));
77 }
78 if time > payload.exp {
80 return Err(format!("已过期: {}", payload.exp));
81 }
82 Ok(payload.exp - time)
83 }
84 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 alg: Alg,
128 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#[derive(Clone)]
173pub struct Payload {
174 pub iss: String,
176 pub iat: i64,
178 pub jti: String,
180
181 pub sub: String,
183 pub aud: String,
185 pub custom: JsonValue,
187
188 pub nbf: i64,
190 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}