async_wechat/official_account/
signature.rs

1use serde::{Deserialize, Serialize};
2use sha1::{Digest, Sha1};
3
4use crate::OfficialAccount;
5
6#[cfg(test)]
7mod tests {
8    use crate::official_account::signature;
9
10    #[tokio::test]
11    async fn request_validate() {
12        let sha1 = "3baae9808b7f85925be470f303cc7b5d035a1c1c".to_string();
13        let sha2 = signature::signature("wechat", "1744100071", "952645420");
14
15        println!("签名: {}", sha1 == sha2);
16    }
17}
18
19#[derive(Debug, Serialize, Deserialize)]
20pub struct WechatQuery {
21    timestamp: String,
22    nonce: String,
23    signature: String,
24    echostr: Option<String>, // 验证时才需要
25}
26
27impl OfficialAccount {
28    /// Checks the signature of the WeChat request to ensure it is
29    /// sent by WeChat.
30    ///
31    /// # Arguments
32    ///
33    /// * `query` - A `WechatQuery` containing the timestamp, nonce, and signature.
34    ///
35    /// # Returns
36    ///
37    /// * `true` if the signature matches, `false` otherwise.
38    pub async fn request_validate(&self, query: WechatQuery) -> bool {
39        let sha1 = signature(&self.config.token, &query.timestamp, &query.nonce);
40        sha1 == query.signature
41    }
42}
43
44/// [消息解密](https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Message_encryption_and_decryption_instructions.html)
45pub fn signature(token: &str, timestamp: &str, nonce: &str) -> String {
46    let mut params = vec![token.to_string(), timestamp.to_string(), nonce.to_string()];
47    params.sort();
48
49    let combined = params.join("");
50
51    let mut hasher = Sha1::new();
52    hasher.update(combined.as_bytes());
53    let result = hasher.finalize();
54
55    format!("{:x}", result)
56}