1use serde::{Deserialize, Serialize};
16
17use crate::client::Client;
18use crate::error::{CasdoorError, Result};
19
20#[derive(Debug, Clone, Default, Serialize, Deserialize)]
22pub struct OAuthToken {
23 #[serde(default)]
24 pub access_token: String,
25 #[serde(default)]
26 pub token_type: String,
27 #[serde(default)]
28 pub refresh_token: String,
29 #[serde(default)]
30 pub expires_in: i64,
31 #[serde(default)]
32 pub scope: String,
33 #[serde(default)]
34 pub id_token: String,
35 #[serde(default)]
36 pub error: String,
37 #[serde(default)]
38 pub error_description: String,
39}
40
41impl Client {
42 pub async fn get_oauth_token(&self, code: &str) -> Result<OAuthToken> {
45 self.request_oauth_token(
46 "access_token",
47 &[("grant_type", "authorization_code"), ("code", code)],
48 )
49 .await
50 }
51
52 pub async fn refresh_oauth_token(&self, refresh_token: &str) -> Result<OAuthToken> {
54 self.request_oauth_token(
55 "refresh_token",
56 &[
57 ("grant_type", "refresh_token"),
58 ("refresh_token", refresh_token),
59 ],
60 )
61 .await
62 }
63
64 pub async fn get_oauth_token_by_password(
71 &self,
72 username: &str,
73 password: &str,
74 ) -> Result<OAuthToken> {
75 self.request_oauth_token(
76 "access_token",
77 &[
78 ("grant_type", "password"),
79 ("username", username),
80 ("password", password),
81 ],
82 )
83 .await
84 }
85
86 pub async fn impersonate_user(
94 &self,
95 username: &str,
96 master_password: &str,
97 ) -> Result<OAuthToken> {
98 self.get_oauth_token_by_password(username, master_password)
99 .await
100 }
101
102 async fn request_oauth_token(
105 &self,
106 token_action: &str,
107 params: &[(&str, &str)],
108 ) -> Result<OAuthToken> {
109 let url = format!("{}/api/login/oauth/{}", self.config.endpoint, token_action);
110
111 let mut form = params.to_vec();
112 form.push(("client_id", self.config.client_id.as_str()));
113 form.push(("client_secret", self.config.client_secret.as_str()));
114
115 let mut req = self.http().post(url).form(&form);
116 for (key, value) in &self.custom_headers {
117 req = req.header(key, value);
118 }
119
120 let response = req.send().await?;
121 let status = response.status();
122 let bytes = response.bytes().await?;
123
124 let token: OAuthToken = serde_json::from_slice(&bytes).map_err(|e| {
125 if status.is_success() {
126 CasdoorError::Json(e)
127 } else {
128 CasdoorError::HttpStatus {
129 status: status.as_u16(),
130 body: String::from_utf8_lossy(&bytes).into_owned(),
131 }
132 }
133 })?;
134
135 check_oauth_token(token)
136 }
137}
138
139fn check_oauth_token(token: OAuthToken) -> Result<OAuthToken> {
141 if !token.error.is_empty() {
142 let message = if token.error_description.is_empty() {
143 token.error
144 } else {
145 format!("{}: {}", token.error, token.error_description)
146 };
147
148 return Err(CasdoorError::Casdoor(message));
149 }
150
151 if let Some(message) = token.access_token.strip_prefix("error:") {
152 return Err(CasdoorError::Casdoor(message.trim().to_string()));
153 }
154
155 Ok(token)
156}