Skip to main content

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::MpResponse;
16use crate::utils::build_request;
17use crate::{Result, constants};
18use async_trait::async_trait;
19use http::Method;
20use std::sync::Arc;
21use tracing::debug;
22
23/// 定义接口调用凭据的行为
24#[async_trait]
25pub trait TokenType: Send + Sync {
26    /// 获取接口调用凭据
27    async fn token(&self) -> Result<AccessToken>;
28    /// 获取应用配置
29    fn app_config(&self) -> AppConfig;
30}
31
32/// 稳定版接口调用凭据
33/// [官方文档](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/stable-token/stableToken.html)
34#[derive(Clone)]
35pub struct StableToken {
36    pub app_id: String,
37    pub secret: String,
38    pub end_point: String,
39    pub force_refresh: bool,
40    client: Arc<dyn HttpClient>,
41}
42
43impl StableToken {
44    pub fn new(
45        app_id: &str,
46        secret: &str,
47        force_refresh: bool,
48        client: Arc<dyn HttpClient>,
49    ) -> Self {
50        StableToken {
51            app_id: app_id.to_string(),
52            secret: secret.to_string(),
53            end_point: constants::STABLE_ACCESS_TOKEN_END_POINT.to_string(),
54            force_refresh,
55            client,
56        }
57    }
58}
59
60/// 稳定版接口调用凭据获取实现
61#[async_trait]
62impl TokenType for StableToken {
63    /// 获取稳定版接口调用凭据
64    async fn token(&self) -> Result<AccessToken> {
65        let body = serde_json::json!({
66            "grant_type":"client_credential",
67            "appid":self.app_id.to_string(),
68            "secret":self.secret.to_string(),
69            "force_refresh":self.force_refresh,
70        });
71        let request = build_request(&self.end_point, Method::POST, None, None, Some(body))?;
72
73        let response = self.client.execute(request).await?;
74        let response_body = response.into_body();
75        let token_builder =
76            serde_json::from_slice::<MpResponse<AccessTokenBuilder>>(&response_body)?;
77        // let token = token_builder.build();
78        let token = token_builder.extract()?;
79        let token = token.build();
80        debug!("stable access token :{:?}", token);
81        Ok(token)
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 body = serde_json::json!({
119            "grant_type":"client_credential",
120            "appid":self.app_id.to_string(),
121            "secret":self.secret.to_string(),
122        });
123        let request = build_request(&self.end_point, Method::POST, None, None, Some(body))?;
124
125        let response = self.client.execute(request).await?;
126        let response_body = response.into_body();
127        let token_builder =
128            serde_json::from_slice::<MpResponse<AccessTokenBuilder>>(&response_body)?;
129        // let token = token_builder.build();
130        let token = token_builder.extract()?;
131        let token = token.build();
132        Ok(token)
133        // let token_builder = serde_json::from_slice::<AccessTokenBuilder>(&response_body)?;
134        // Ok(token_builder.build())
135    }
136
137    /// 获取应用配置
138    fn app_config(&self) -> AppConfig {
139        AppConfig {
140            app_id: self.app_id.clone(),
141            secret: self.secret.clone(),
142        }
143    }
144}