authz_sdk_rust/
sign.rs

1use std::{collections::HashMap, str::FromStr};
2
3use chrono::Utc;
4use jsonwebtoken::{crypto::sign, Algorithm, EncodingKey};
5use reqwest::{
6    header::{HeaderName, HeaderValue},
7    Method, Request, Url,
8};
9use serde::{Deserialize, Serialize};
10
11use crate::{Error, Result};
12
13#[derive(Debug, Deserialize, Serialize)]
14pub struct Signature {
15    pub access_key: String,
16    pub algorithm: String,
17    pub request_time: String,
18    pub sign: String,
19    pub signed_headers: String,
20}
21
22#[derive(Debug, Serialize, Ord, Eq, PartialOrd, PartialEq)]
23struct SignHeader {
24    pub key: String,
25    pub value: String,
26}
27
28pub fn signature(
29    value: &mut Signature,
30    sign_headers: HashMap<String, String>,
31    secret_access_key: String,
32    seconds_offset: u64,
33) -> Result<String> {
34    // 校验时间
35    let request_time = value.request_time.parse::<i64>().map_err(Error::any)?;
36    let now = Utc::now().timestamp();
37    if now.abs_diff(request_time).gt(&seconds_offset) {
38        return Err(Error::Invalid("time span exceeds threshold".to_string()));
39    }
40    // 解析算法
41    let algorithm = Algorithm::from_str(&value.algorithm).map_err(Error::any)?;
42
43    // sign 签名生成
44    value.sign = Default::default();
45    let message = serde_json::to_string(&value).map_err(Error::any)?;
46    // 校验头排序
47    let mut sort_headers = Vec::new();
48    for h in value
49        .signed_headers
50        .split(';')
51        .collect::<Vec<&str>>()
52        .iter()
53    {
54        match sign_headers.get_key_value(*h) {
55            Some((k, v)) => sort_headers.push(SignHeader {
56                key: k.to_owned(),
57                value: v.to_owned(),
58            }),
59            None => return Err(Error::Invalid(format!("lack {}", *h))),
60        }
61    }
62    sort_headers.sort();
63    let signature = serde_json::to_string(&sort_headers).map_err(Error::any)?;
64    let sign_result = sign(
65        [message, signature].join(".").as_bytes(),
66        &EncodingKey::from_secret(secret_access_key.as_bytes()),
67        algorithm,
68    )
69    .map_err(Error::any)?;
70    Ok(sign_result)
71}
72
73pub fn query(
74    value: &mut Signature,
75    sign_headers: HashMap<String, String>,
76    secret_access_key: String,
77    seconds_offset: u64,
78) -> Result<String> {
79    value.sign = signature(
80        value,
81        sign_headers.clone(),
82        secret_access_key,
83        seconds_offset,
84    )?;
85    let prefix = serde_urlencoded::to_string(value).map_err(Error::any)?;
86    let suffix = serde_urlencoded::to_string(sign_headers).map_err(Error::any)?;
87    Ok([prefix, suffix].join("&"))
88}
89
90pub fn request(
91    method: Method,
92    url: Url,
93    value: &mut Signature,
94    sign_headers: HashMap<String, String>,
95    secret_access_key: String,
96) -> Result<Request> {
97    // default 15s
98    value.sign = signature(value, sign_headers.clone(), secret_access_key, 15)?;
99    let mut req = Request::new(method, url);
100
101    req.headers_mut().append(
102        HeaderName::from_static("access_key"),
103        HeaderValue::from_str(&value.access_key).map_err(Error::any)?,
104    );
105    req.headers_mut().append(
106        HeaderName::from_static("algorithm"),
107        HeaderValue::from_str(&value.algorithm).map_err(Error::any)?,
108    );
109    req.headers_mut().append(
110        HeaderName::from_static("request_time"),
111        HeaderValue::from_str(&value.request_time).map_err(Error::any)?,
112    );
113    req.headers_mut().append(
114        HeaderName::from_static("sign"),
115        HeaderValue::from_str(&value.sign).map_err(Error::any)?,
116    );
117    req.headers_mut().append(
118        HeaderName::from_static("signed_headers"),
119        HeaderValue::from_str(&value.signed_headers).map_err(Error::any)?,
120    );
121    for (k, v) in sign_headers.iter() {
122        req.headers_mut().append(
123            HeaderName::from_str(k).map_err(Error::any)?,
124            HeaderValue::from_str(v.as_str()).map_err(Error::any)?,
125        );
126    }
127    Ok(req)
128}