open_lark/core/request_builder/
auth_handler.rs1use crate::core::{
2 config::Config, constants::AccessTokenType, error::LarkAPIError, req_option::RequestOption,
3};
4use reqwest::RequestBuilder;
5
6pub struct AuthHandler;
8
9impl AuthHandler {
10 pub async fn apply_auth(
12 req_builder: RequestBuilder,
13 access_token_type: AccessTokenType,
14 config: &Config,
15 option: &RequestOption,
16 ) -> Result<RequestBuilder, LarkAPIError> {
17 match access_token_type {
18 AccessTokenType::None => Ok(req_builder),
19 AccessTokenType::App => Self::apply_app_auth(req_builder, config, option).await,
20 AccessTokenType::Tenant => Self::apply_tenant_auth(req_builder, config, option).await,
21 AccessTokenType::User => Ok(Self::apply_user_auth(req_builder, option)),
22 }
23 }
24
25 async fn apply_app_auth(
27 req_builder: RequestBuilder,
28 config: &Config,
29 option: &RequestOption,
30 ) -> Result<RequestBuilder, LarkAPIError> {
31 let app_access_token = if !option.app_access_token.is_empty() {
32 option.app_access_token.clone()
33 } else if config.enable_token_cache {
34 let token_manager = config.token_manager.lock().await;
35 token_manager
36 .get_app_access_token(config, &option.app_ticket, &config.app_ticket_manager)
37 .await?
38 } else {
39 return Err(LarkAPIError::MissingAccessToken);
40 };
41
42 Ok(Self::add_auth_header(req_builder, &app_access_token))
43 }
44
45 async fn apply_tenant_auth(
47 req_builder: RequestBuilder,
48 config: &Config,
49 option: &RequestOption,
50 ) -> Result<RequestBuilder, LarkAPIError> {
51 let tenant_access_token = if !option.tenant_access_token.is_empty() {
52 option.tenant_access_token.clone()
53 } else if config.enable_token_cache {
54 let token_manager = config.token_manager.lock().await;
55 token_manager
56 .get_tenant_access_token(
57 config,
58 &option.tenant_key,
59 &option.app_ticket,
60 &config.app_ticket_manager,
61 )
62 .await?
63 } else {
64 return Err(LarkAPIError::MissingAccessToken);
65 };
66
67 Ok(Self::add_auth_header(req_builder, &tenant_access_token))
68 }
69
70 fn apply_user_auth(req_builder: RequestBuilder, option: &RequestOption) -> RequestBuilder {
72 Self::add_auth_header(req_builder, &option.user_access_token)
73 }
74
75 fn add_auth_header(req_builder: RequestBuilder, token: &str) -> RequestBuilder {
77 req_builder.header("Authorization", format!("Bearer {token}"))
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::core::constants::AppType;
85 use reqwest::Client;
86
87 fn create_test_config() -> Config {
88 Config::builder()
89 .app_id("test_app_id")
90 .app_secret("test_app_secret")
91 .app_type(AppType::SelfBuild)
92 .enable_token_cache(false)
93 .build()
94 }
95
96 fn create_test_request_builder() -> RequestBuilder {
97 Client::new().get("https://test.api.example.com/test")
98 }
99
100 #[test]
101 fn test_auth_handler_struct_creation() {
102 let _handler = AuthHandler;
103 }
104
105 #[tokio::test]
106 async fn test_apply_auth_none_type() {
107 let req_builder = create_test_request_builder();
108 let config = create_test_config();
109 let option = RequestOption::default();
110
111 let result =
112 AuthHandler::apply_auth(req_builder, AccessTokenType::None, &config, &option).await;
113
114 assert!(result.is_ok());
115 }
116
117 #[tokio::test]
118 async fn test_apply_auth_user_type() {
119 let req_builder = create_test_request_builder();
120 let config = create_test_config();
121 let option = RequestOption {
122 user_access_token: "user_token_123".to_string(),
123 ..Default::default()
124 };
125
126 let result =
127 AuthHandler::apply_auth(req_builder, AccessTokenType::User, &config, &option).await;
128
129 assert!(result.is_ok());
130 }
131
132 #[tokio::test]
133 async fn test_apply_app_auth_with_token_in_option() {
134 let req_builder = create_test_request_builder();
135 let config = create_test_config();
136 let option = RequestOption {
137 app_access_token: "app_token_123".to_string(),
138 ..Default::default()
139 };
140
141 let result = AuthHandler::apply_app_auth(req_builder, &config, &option).await;
142 assert!(result.is_ok());
143 }
144
145 #[tokio::test]
146 async fn test_apply_app_auth_no_cache_no_token() {
147 let req_builder = create_test_request_builder();
148 let config = create_test_config(); let option = RequestOption::default(); let result = AuthHandler::apply_app_auth(req_builder, &config, &option).await;
152 assert!(result.is_err());
153
154 match result {
155 Err(LarkAPIError::MissingAccessToken) => (),
156 _ => panic!("Expected MissingAccessToken error"),
157 }
158 }
159
160 #[tokio::test]
161 async fn test_apply_tenant_auth_with_token_in_option() {
162 let req_builder = create_test_request_builder();
163 let config = create_test_config();
164 let option = RequestOption {
165 tenant_access_token: "tenant_token_123".to_string(),
166 ..Default::default()
167 };
168
169 let result = AuthHandler::apply_tenant_auth(req_builder, &config, &option).await;
170 assert!(result.is_ok());
171 }
172
173 #[tokio::test]
174 async fn test_apply_tenant_auth_no_cache_no_token() {
175 let req_builder = create_test_request_builder();
176 let config = create_test_config(); let option = RequestOption::default(); let result = AuthHandler::apply_tenant_auth(req_builder, &config, &option).await;
180 assert!(result.is_err());
181
182 match result {
183 Err(LarkAPIError::MissingAccessToken) => (),
184 _ => panic!("Expected MissingAccessToken error"),
185 }
186 }
187
188 #[test]
189 fn test_apply_user_auth() {
190 let req_builder = create_test_request_builder();
191 let option = RequestOption {
192 user_access_token: "user_token_456".to_string(),
193 ..Default::default()
194 };
195
196 let result = AuthHandler::apply_user_auth(req_builder, &option);
197
198 assert!(format!("{:?}", result).contains("RequestBuilder"));
201 }
202
203 #[test]
204 fn test_add_auth_header_with_token() {
205 let req_builder = create_test_request_builder();
206 let token = "test_token_789";
207
208 let result = AuthHandler::add_auth_header(req_builder, token);
209
210 assert!(format!("{:?}", result).contains("RequestBuilder"));
213 }
214
215 #[test]
216 fn test_add_auth_header_with_empty_token() {
217 let req_builder = create_test_request_builder();
218 let token = "";
219
220 let result = AuthHandler::add_auth_header(req_builder, token);
221
222 assert!(format!("{:?}", result).contains("RequestBuilder"));
224 }
225
226 #[tokio::test]
227 async fn test_apply_auth_all_types() {
228 let config = create_test_config();
229
230 let test_cases = vec![
231 (AccessTokenType::None, RequestOption::default()),
232 (
233 AccessTokenType::User,
234 RequestOption {
235 user_access_token: "user_token".to_string(),
236 ..Default::default()
237 },
238 ),
239 (
240 AccessTokenType::App,
241 RequestOption {
242 app_access_token: "app_token".to_string(),
243 ..Default::default()
244 },
245 ),
246 (
247 AccessTokenType::Tenant,
248 RequestOption {
249 tenant_access_token: "tenant_token".to_string(),
250 ..Default::default()
251 },
252 ),
253 ];
254
255 for (token_type, option) in test_cases {
256 let req_builder = create_test_request_builder();
257
258 let result = AuthHandler::apply_auth(req_builder, token_type, &config, &option).await;
259
260 match token_type {
263 AccessTokenType::None | AccessTokenType::User => {
264 assert!(result.is_ok());
265 }
266 AccessTokenType::App | AccessTokenType::Tenant => {
267 assert!(result.is_ok());
269 }
270 }
271 }
272 }
273
274 #[tokio::test]
275 async fn test_apply_auth_with_cache_enabled() {
276 let config = Config::builder()
277 .app_id("test_app_id")
278 .app_secret("test_app_secret")
279 .app_type(AppType::SelfBuild)
280 .enable_token_cache(true)
281 .build();
282
283 let option = RequestOption::default();
284 let req_builder = create_test_request_builder();
285
286 let result =
289 AuthHandler::apply_auth(req_builder, AccessTokenType::App, &config, &option).await;
290
291 assert!(result.is_ok() || result.is_err());
293 }
294
295 #[test]
296 fn test_auth_handler_trait_implementations() {
297 fn assert_send<T: Send>() {}
299 fn assert_sync<T: Sync>() {}
300
301 assert_send::<AuthHandler>();
302 assert_sync::<AuthHandler>();
303 }
304
305 #[test]
306 fn test_add_auth_header_format() {
307 let req_builder = create_test_request_builder();
308 let token = "test123";
309
310 let _result = AuthHandler::add_auth_header(req_builder, token);
311
312 }
316}