wechat_minapp/client/
token_type.rs

1//! 接口调用凭据类型模块
2//! 分为普通接口调用凭据和稳定版接口调用凭据
3//! 普通接口调用凭据使用场景:
4//! 1. 适用于大多数微信小程序后台服务API调用场景
5//! 2. 适用于对访问令牌实时性要求较高的场景
6//! 稳定版接口调用凭据使用场景:
7//! 1. 适用于需要长期稳定访问令牌的场景
8//! 2. 适用于对访问令牌实时性要求不高,但需要确保访问令牌长期有效的场景 
9//! 
10
11
12use super::access_token::AccessTokenBuilder;
13use super::{AccessToken, AppConfig, HttpClient};
14use crate::{Result, constants};
15use async_trait::async_trait;
16use http::{Method, Request};
17use std::collections::HashMap;
18use std::sync::Arc;
19
20/// 定义接口调用凭据的行为
21#[async_trait]
22pub trait TokenType: Send + Sync {
23    /// 获取接口调用凭据
24    async fn token(&self) -> Result<AccessToken>;
25    /// 获取应用配置
26    fn app_config(&self) -> AppConfig;
27}
28
29/// 稳定版接口调用凭据
30/// [官方文档](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/stable-token/stableToken.html)
31#[derive(Clone)]
32pub struct StableToken {
33    pub app_id: String,
34    pub secret: String,
35    pub end_point: String,
36    pub force_refresh: bool,
37    client: Arc<dyn HttpClient>,
38}
39
40impl StableToken {
41    pub fn new(
42        app_id: &str,
43        secret: &str,
44        force_refresh: bool,
45        client: Arc<dyn HttpClient>,
46    ) -> Self {
47        StableToken {
48            app_id: app_id.to_string(),
49            secret: secret.to_string(),
50            end_point: constants::STABLE_ACCESS_TOKEN_END_POINT.to_string(),
51            force_refresh,
52            client,
53        }
54    }
55}
56
57/// 稳定版接口调用凭据获取实现
58#[async_trait]
59impl TokenType for StableToken {
60    /// 获取稳定版接口调用凭据
61    async fn token(&self) -> Result<AccessToken> {
62        let mut body: HashMap<&str, String> = HashMap::new();
63        body.insert("grant_type", "client_credential".into());
64        body.insert("appid", self.app_id.to_string());
65        body.insert("secret", self.secret.to_string());
66
67        if self.force_refresh {
68            body.insert("force_refresh", self.force_refresh.to_string());
69        }
70        let req_body = serde_json::to_vec(&body)?;
71        let request = Request::builder()
72            .uri(self.end_point.clone())
73            .method(Method::POST)
74            .header("User-Agent", constants::HTTP_CLIENT_USER_AGENT)
75            .body(req_body)?;
76
77        let response = self.client.execute(request).await?;
78        let response_body = response.into_body();
79        let token_builder = serde_json::from_slice::<AccessTokenBuilder>(&response_body)?;
80        Ok(token_builder.build())
81    }
82
83    /// 获取应用配置
84    fn app_config(&self) -> AppConfig {
85        AppConfig {
86            app_id: self.app_id.clone(),
87            secret: self.secret.clone(),
88        }
89    }
90}
91
92/// 普通接口调用凭据
93/// [官方文档](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/access-token/accessToken.html)
94pub struct NonStableToken {
95    pub app_id: String,
96    pub secret: String,
97    pub end_point: String,
98    client: Arc<dyn HttpClient>,
99}
100
101impl NonStableToken {
102    pub fn new(app_id: &str, secret: &str, client: Arc<dyn HttpClient>) -> Self {
103        NonStableToken {
104            app_id: app_id.to_string(),
105            secret: secret.to_string(),
106            end_point: constants::ACCESS_TOKEN_END_POINT.to_string(),
107            client,
108        }
109    }
110}
111
112/// 普通接口调用凭据获取实现
113#[async_trait]
114impl TokenType for NonStableToken {
115    /// 获取普通接口调用凭据
116    async fn token(&self) -> Result<AccessToken> {
117        let mut body: HashMap<&str, String> = HashMap::new();
118        body.insert("grant_type", "client_credential".into());
119        body.insert("appid", self.app_id.to_string());
120        body.insert("secret", self.secret.to_string());
121
122        let req_body = serde_json::to_vec(&body)?;
123        let request = Request::builder()
124            .uri(self.end_point.clone())
125            .method(Method::POST)
126            .header("User-Agent", constants::HTTP_CLIENT_USER_AGENT)
127            .body(req_body)?;
128
129        let response = self.client.execute(request).await?;
130        let response_body = response.into_body();
131        let token_builder = serde_json::from_slice::<AccessTokenBuilder>(&response_body)?;
132        Ok(token_builder.build())
133    }
134
135    /// 获取应用配置
136    fn app_config(&self) -> AppConfig {
137        AppConfig {
138            app_id: self.app_id.clone(),
139            secret: self.secret.clone(),
140        }
141    }
142}