wechat_minapp/client/
token_type.rs

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