Skip to main content

wae_schema/openapi/
security.rs

1//! OpenAPI 安全定义
2
3use serde::{Deserialize, Serialize};
4
5/// 安全要求
6#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7pub struct SecurityRequirement {
8    /// 安全方案名称和范围
9    #[serde(flatten)]
10    pub schemes: std::collections::BTreeMap<String, Vec<String>>,
11}
12
13impl SecurityRequirement {
14    /// 创建新的安全要求
15    pub fn new() -> Self {
16        Self::default()
17    }
18
19    /// 添加安全方案
20    pub fn scheme(mut self, name: impl Into<String>, scopes: Vec<&str>) -> Self {
21        self.schemes.insert(name.into(), scopes.into_iter().map(String::from).collect());
22        self
23    }
24}
25
26/// 安全方案类型
27#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28#[serde(rename_all = "lowercase")]
29pub enum SecuritySchemeType {
30    /// API Key
31    ApiKey,
32    /// HTTP 认证
33    Http,
34    /// OAuth2
35    OAuth2,
36    /// OpenID Connect
37    OpenIdConnect,
38}
39
40/// API Key 位置
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
42#[serde(rename_all = "lowercase")]
43pub enum ApiKeyLocation {
44    /// 查询参数
45    Query,
46    /// 请求头
47    Header,
48    /// Cookie
49    Cookie,
50}
51
52/// 安全方案
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct SecurityScheme {
55    /// 安全方案类型
56    #[serde(rename = "type")]
57    pub scheme_type: SecuritySchemeType,
58    /// 安全方案描述
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub description: Option<String>,
61    /// API Key 名称(仅 apiKey 类型)
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub name: Option<String>,
64    /// API Key 位置(仅 apiKey 类型)
65    #[serde(rename = "in")]
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub location: Option<ApiKeyLocation>,
68    /// HTTP 方案名称(仅 http 类型)
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub scheme: Option<String>,
71    /// HTTP Bearer 格式(仅 http 类型)
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub bearer_format: Option<String>,
74    /// OAuth2 流程(仅 oauth2 类型)
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub flows: Option<OAuthFlows>,
77    /// OpenID Connect URL(仅 openIdConnect 类型)
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub open_id_connect_url: Option<String>,
80}
81
82impl SecurityScheme {
83    /// 创建 API Key 安全方案
84    pub fn api_key(name: impl Into<String>, location: ApiKeyLocation) -> Self {
85        Self {
86            scheme_type: SecuritySchemeType::ApiKey,
87            description: None,
88            name: Some(name.into()),
89            location: Some(location),
90            scheme: None,
91            bearer_format: None,
92            flows: None,
93            open_id_connect_url: None,
94        }
95    }
96
97    /// 创建 HTTP Basic 安全方案
98    pub fn basic() -> Self {
99        Self {
100            scheme_type: SecuritySchemeType::Http,
101            description: None,
102            name: None,
103            location: None,
104            scheme: Some("basic".to_string()),
105            bearer_format: None,
106            flows: None,
107            open_id_connect_url: None,
108        }
109    }
110
111    /// 创建 HTTP Bearer 安全方案
112    pub fn bearer(format: Option<String>) -> Self {
113        Self {
114            scheme_type: SecuritySchemeType::Http,
115            description: None,
116            name: None,
117            location: None,
118            scheme: Some("bearer".to_string()),
119            bearer_format: format,
120            flows: None,
121            open_id_connect_url: None,
122        }
123    }
124
125    /// 创建 OAuth2 安全方案
126    pub fn oauth2(flows: OAuthFlows) -> Self {
127        Self {
128            scheme_type: SecuritySchemeType::OAuth2,
129            description: None,
130            name: None,
131            location: None,
132            scheme: None,
133            bearer_format: None,
134            flows: Some(flows),
135            open_id_connect_url: None,
136        }
137    }
138
139    /// 创建 OpenID Connect 安全方案
140    pub fn open_id_connect(url: impl Into<String>) -> Self {
141        Self {
142            scheme_type: SecuritySchemeType::OpenIdConnect,
143            description: None,
144            name: None,
145            location: None,
146            scheme: None,
147            bearer_format: None,
148            flows: None,
149            open_id_connect_url: Some(url.into()),
150        }
151    }
152
153    /// 设置描述
154    pub fn description(mut self, desc: impl Into<String>) -> Self {
155        self.description = Some(desc.into());
156        self
157    }
158}
159
160/// OAuth2 流程
161#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct OAuthFlows {
163    /// Implicit 流程
164    #[serde(skip_serializing_if = "Option::is_none")]
165    pub implicit: Option<OAuthFlow>,
166    /// Password 流程
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub password: Option<OAuthFlow>,
169    /// Client Credentials 流程
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub client_credentials: Option<OAuthFlow>,
172    /// Authorization Code 流程
173    #[serde(skip_serializing_if = "Option::is_none")]
174    pub authorization_code: Option<OAuthFlow>,
175}
176
177/// OAuth2 流程
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct OAuthFlow {
180    /// 授权 URL
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub authorization_url: Option<String>,
183    /// Token URL
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub token_url: Option<String>,
186    /// 刷新 URL
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub refresh_url: Option<String>,
189    /// 可用的范围
190    pub scopes: std::collections::BTreeMap<String, String>,
191}
192
193impl OAuthFlow {
194    /// 创建新的 OAuth 流程
195    pub fn new() -> Self {
196        Self { authorization_url: None, token_url: None, refresh_url: None, scopes: std::collections::BTreeMap::new() }
197    }
198
199    /// 设置授权 URL
200    pub fn authorization_url(mut self, url: impl Into<String>) -> Self {
201        self.authorization_url = Some(url.into());
202        self
203    }
204
205    /// 设置 Token URL
206    pub fn token_url(mut self, url: impl Into<String>) -> Self {
207        self.token_url = Some(url.into());
208        self
209    }
210
211    /// 设置刷新 URL
212    pub fn refresh_url(mut self, url: impl Into<String>) -> Self {
213        self.refresh_url = Some(url.into());
214        self
215    }
216
217    /// 添加范围
218    pub fn scope(mut self, name: impl Into<String>, description: impl Into<String>) -> Self {
219        self.scopes.insert(name.into(), description.into());
220        self
221    }
222}
223
224impl Default for OAuthFlow {
225    fn default() -> Self {
226        Self::new()
227    }
228}