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::utils::build_request;
16use crate::{Result, constants};
17use async_trait::async_trait;
18use http::Method;
19use std::sync::Arc;
20use tracing::debug;
21
22/// 定义接口调用凭据的行为
23#[async_trait]
24pub trait TokenType: Send + Sync {
25    /// 获取接口调用凭据
26    async fn token(&self) -> Result<AccessToken>;
27    /// 获取应用配置
28    fn app_config(&self) -> AppConfig;
29}
30
31/// 稳定版接口调用凭据
32/// [官方文档](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/stable-token/stableToken.html)
33#[derive(Clone)]
34pub struct StableToken {
35    pub app_id: String,
36    pub secret: String,
37    pub end_point: String,
38    pub force_refresh: bool,
39    client: Arc<dyn HttpClient>,
40}
41
42impl StableToken {
43    pub fn new(
44        app_id: &str,
45        secret: &str,
46        force_refresh: bool,
47        client: Arc<dyn HttpClient>,
48    ) -> Self {
49        StableToken {
50            app_id: app_id.to_string(),
51            secret: secret.to_string(),
52            end_point: constants::STABLE_ACCESS_TOKEN_END_POINT.to_string(),
53            force_refresh,
54            client,
55        }
56    }
57}
58
59/// 稳定版接口调用凭据获取实现
60#[async_trait]
61impl TokenType for StableToken {
62    /// 获取稳定版接口调用凭据
63    async fn token(&self) -> Result<AccessToken> {
64        let body = serde_json::json!({
65            "grant_type":"client_credential",
66            "appid":self.app_id.to_string(),
67            "secret":self.secret.to_string(),
68            "force_refresh":self.force_refresh,
69        });
70        let request = build_request(&self.end_point, Method::POST, None, None, Some(body))?;
71
72        let response = self.client.execute(request).await?;
73        let response_body = response.into_body();
74        let token_builder = serde_json::from_slice::<AccessTokenBuilder>(&response_body)?;
75        let token = token_builder.build();
76        debug!("stable access token :{:?}", token);
77        Ok(token)
78    }
79
80    /// 获取应用配置
81    fn app_config(&self) -> AppConfig {
82        AppConfig {
83            app_id: self.app_id.clone(),
84            secret: self.secret.clone(),
85        }
86    }
87}
88
89/// 普通接口调用凭据
90/// [官方文档](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/access-token/accessToken.html)
91pub struct NonStableToken {
92    pub app_id: String,
93    pub secret: String,
94    pub end_point: String,
95    client: Arc<dyn HttpClient>,
96}
97
98impl NonStableToken {
99    pub fn new(app_id: &str, secret: &str, client: Arc<dyn HttpClient>) -> Self {
100        NonStableToken {
101            app_id: app_id.to_string(),
102            secret: secret.to_string(),
103            end_point: constants::ACCESS_TOKEN_END_POINT.to_string(),
104            client,
105        }
106    }
107}
108
109/// 普通接口调用凭据获取实现
110#[async_trait]
111impl TokenType for NonStableToken {
112    /// 获取普通接口调用凭据
113    async fn token(&self) -> Result<AccessToken> {
114        let body = serde_json::json!({
115            "grant_type":"client_credential",
116            "appid":self.app_id.to_string(),
117            "secret":self.secret.to_string(),
118        });
119        let request = build_request(&self.end_point, Method::POST, None, None, Some(body))?;
120
121        let response = self.client.execute(request).await?;
122        let response_body = response.into_body();
123        let token_builder = serde_json::from_slice::<AccessTokenBuilder>(&response_body)?;
124        Ok(token_builder.build())
125    }
126
127    /// 获取应用配置
128    fn app_config(&self) -> AppConfig {
129        AppConfig {
130            app_id: self.app_id.clone(),
131            secret: self.secret.clone(),
132        }
133    }
134}