df-crypto 0.1.5

This is an crypto
Documentation
use chrono::Local;
use json::{JsonValue, object};
use log::info;
use crate::base64::{url_decode, url_encode};
use crate::hmac::str_to_hmacsha256;

pub struct Jwt {
    header: JsonValue,
    payload: JsonValue,
}

impl Jwt {
    /// 初始化
    ///
    /// * iss 签发人
    pub fn default(iss: &str) -> Self {
        Self {
            header: object! {
                "alg":"HS256",
                "typ": "JWT"
            },
            payload: object! {
                "iss":iss.clone(),
                "iat":Local::now().timestamp(),
                "jti":uuid::Uuid::new_v4().to_string()
            },
        }
    }
    /// token信息
    ///
    /// * sub 主题
    /// * aud 受众
    /// * custom 自定义内容
    pub fn payload(&mut self, sub: &str, aud: &str, custom: JsonValue) -> &mut Self {
        self.payload["sub"] = sub.into();
        self.payload["aud"] = aud.into();
        self.payload["custom"] = custom.into();
        self
    }
    /// 生效时间与过期时间设置
    ///
    /// * nbf 生效时间
    /// * exp 过期时间 分钟
    pub fn nbf_exp(&mut self, nbf: i64, exp: i64) -> &mut Self {
        if nbf == 0 {
            self.payload["nbf"] = (Local::now().timestamp()).into();
        } else {
            self.payload["nbf"] = nbf.into();
        }
        let nbf = self.payload["nbf"].as_i64().unwrap();
        let exp = 60 * exp * 1000;
        self.payload["exp"] = (nbf + exp).into();
        self
    }
    /// 返回口令
    ///
    /// * key 加密密钥
    pub fn sign(&mut self, key: &str) -> String {
        let header = url_encode(self.header.to_string());
        let payload = url_encode(self.payload.to_string());
        let signature = format!("{}.{}", header, payload);
        let data = str_to_hmacsha256(key.clone(), signature.as_str().clone());
        let sign = url_encode(data.to_string());
        let token = format!("{}.{}.{}", header, payload, sign);
        return token;
    }
    /// 验证
    pub fn verify(token: &str, key: &str) -> bool {
        let binding = token.to_string();
        let data: Vec<&str> = binding.split(".").collect();
        if data.len() < 3 {
            return false;
        }
        let header = data[0].clone();
        let payload = data[1].clone();
        let signature = format!("{}.{}", header, payload);
        let sign_old = data[2].clone();

        let header = url_decode(header.to_string());
        let header = json::parse(header.as_str()).unwrap();
        let alg = header["alg"].as_str().unwrap();
        let sign_new = {
            match alg {
                "HS256" => {
                    let hmacsha256 = str_to_hmacsha256(key.clone(), signature.as_str().clone());
                    url_encode(hmacsha256)
                }
                _ => {
                    signature
                }
            }
        };
        if sign_new != sign_old {
            return false;
        }
        let payload_text = url_decode(payload.to_string());
        match json::parse(payload_text.as_str()) {
            Ok(payload) => {
                let time = Local::now().timestamp();
                // 生效时间早于当前时间
                let nbf = payload["nbf"].as_i64().unwrap();
                if nbf > time {
                    return false;
                }
                // 过期时间小于当前时间
                let exp = payload["exp"].as_i64().unwrap();
                if time > exp {
                    return false;
                }
                return true;
            }
            Err(e) => {
                info!("{}",e);
                info!("payload_old:{}",payload);
                info!("payload_new:{}",payload_text);
                return false;
            }
        }
    }
    /// 信息
    pub fn info(token: &str) -> JsonValue {
        let binding = token.to_string();
        let data: Vec<&str> = binding.split(".").collect();
        let header = data[0].clone();
        let payload = data[1].clone();
        let header = url_decode(header.to_string());
        let header = {
            let res = json::parse(header.as_str());
            match res {
                Ok(e) => e,
                Err(_) => object! {}
            }
        };
        let payload = url_decode(payload.to_string());
        let payload = {
            let res = json::parse(payload.as_str());
            match res {
                Ok(e) => e,
                Err(_) => object! {}
            }
        };
        return object! {
            "header":header,
            "payload":payload
        };
    }
}