df-crypto 0.1.2

This is an crypto
Documentation
use chrono::Local;
use json::{JsonValue, object};
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha256;
use log::info;
use crate::base64::{decode, url_decode, url_encode, url_encode_u8};

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_millis(),
                "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: &str, exp: i64) -> &mut Self {
        if nbf == "" {
            self.payload["nbf"] = Local::now().timestamp_millis().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 mut hmac = Hmac::new(Sha256::new(), key.as_bytes());
        hmac.input(signature.as_bytes());
        let mac = hmac.result();
        let sign = url_encode_u8(mac.code());
        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();
        let header = data[0].clone();
        let payload = data[1].clone();
        let signature = format!("{}.{}", header, payload);
        let sign_old = data[2].clone();

        let header = 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 mut hmac = Hmac::new(Sha256::new(), key.as_bytes());
                    hmac.input(signature.as_bytes());
                    let mac = hmac.result();
                    url_encode_u8(mac.code())
                }
                _ => {
                    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_millis();
                // 过期时间小于当前时间
                let exp = payload["exp"].as_i64().unwrap();
                if time >= exp {
                    return false;
                }
                // 生效时间早于当前时间
                let nbf = payload["nbf"].as_i64().unwrap();
                if nbf > time {
                    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 = 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
        };
    }
}