From 35cbdd77a791cf0c95aea6b36d9aad744785b3ca Mon Sep 17 00:00:00 2001 From: Kirill Kinduk Date: Tue, 9 Jul 2024 13:28:45 +0300 Subject: [PATCH 1/3] feat(aide): added security schemes --- crates/aide/src/axum/mod.rs | 4 ++++ crates/aide/src/gen.rs | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/aide/src/axum/mod.rs b/crates/aide/src/axum/mod.rs index ba278229..e7fcbe02 100644 --- a/crates/aide/src/axum/mod.rs +++ b/crates/aide/src/axum/mod.rs @@ -393,6 +393,10 @@ where let components = api.components.get_or_insert_with(Default::default); + components + .security_schemes + .extend(ctx.security_schemes.drain()); + components .schemas .extend(ctx.schema.take_definitions().into_iter().map( diff --git a/crates/aide/src/gen.rs b/crates/aide/src/gen.rs index 20deafa6..cfa4bbea 100644 --- a/crates/aide/src/gen.rs +++ b/crates/aide/src/gen.rs @@ -49,9 +49,7 @@ pub fn on_error(handler: impl Fn(Error) + 'static) { /// /// [`OpenApi`]: crate::openapi::OpenApi pub fn extract_schemas(extract: bool) { - in_context(|ctx| { - ctx.set_extract_schemas(extract) - }); + in_context(|ctx| ctx.set_extract_schemas(extract)); } /// Set the inferred status code of empty responses (`()`). @@ -105,6 +103,12 @@ pub struct GenContext { /// for generating JSON schemas. pub schema: SchemaGenerator, + /// Secutiry schemes descriptions. + pub security_schemes: std::collections::HashMap< + String, + crate::openapi::ReferenceOr, + >, + pub(crate) infer_responses: bool, pub(crate) all_error_responses: bool, @@ -134,6 +138,7 @@ impl GenContext { let mut this = Self { schema: SchemaGenerator::new(SchemaSettings::draft07()), + security_schemes: std::collections::HashMap::new(), infer_responses: true, all_error_responses: false, extract_schemas: true, From 254ea03a10dea3facf5a4d709e6ad924e5a1131e Mon Sep 17 00:00:00 2001 From: Kirill Kinduk Date: Tue, 9 Jul 2024 13:30:44 +0300 Subject: [PATCH 2/3] fix(aide): proper jwt authorizer implementation via security schemes --- crates/aide/src/axum/inputs.rs | 42 ++++++++++++---------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/crates/aide/src/axum/inputs.rs b/crates/aide/src/axum/inputs.rs index 94138358..d0ad5c73 100644 --- a/crates/aide/src/axum/inputs.rs +++ b/crates/aide/src/axum/inputs.rs @@ -2,15 +2,14 @@ use crate::{ openapi::{ self, Header, MediaType, Operation, Parameter, ParameterData, ReferenceOr, RequestBody, - Response, SchemaObject, StatusCode, + Response, SchemaObject, SecurityScheme, StatusCode, }, operation::{add_parameters, set_body}, }; use axum::{ body::Body, extract::{ - Extension, Form, Host, Json, MatchedPath, OriginalUri, Path, Query, RawQuery, - State, + Extension, Form, Host, Json, MatchedPath, OriginalUri, Path, Query, RawQuery, State, }, }; @@ -410,6 +409,8 @@ mod extra { #[cfg(feature = "jwt-authorizer")] mod jwt_authorizer { + use std::any::type_name; + use super::*; use crate::OperationInput; use ::jwt_authorizer::JwtClaims; @@ -419,31 +420,18 @@ mod jwt_authorizer { ctx: &mut crate::gen::GenContext, operation: &mut crate::openapi::Operation, ) { - let s = ctx.schema.subschema_for::(); - add_parameters( - ctx, - operation, - [Parameter::Header { - parameter_data: ParameterData { - name: "Authorization".to_string(), - description: Some("Jwt Bearer token".to_string()), - required: true, - format: crate::openapi::ParameterSchemaOrContent::Schema( - openapi::SchemaObject { - json_schema: s, - example: None, - external_docs: None, - }, - ), - extensions: Default::default(), - deprecated: None, - example: None, - examples: IndexMap::default(), - explode: None, - }, - style: openapi::HeaderStyle::Simple, - }], + let t = "JWT Authorizer".to_string(); + ctx.security_schemes.insert( + t.clone(), + ReferenceOr::Item(SecurityScheme::Http { + scheme: "Bearer".to_string(), + bearer_format: Some("JWT".to_string()), + description: Some("A bearer token.".to_string()), + extensions: Default::default(), + }), ); + + operation.security.push([(t, Vec::new())].into()) } } } From d3b142a488d6ac68af6f1913a834cb4d669ee4ea Mon Sep 17 00:00:00 2001 From: Kirill Kinduk Date: Fri, 2 Aug 2024 11:32:47 +0300 Subject: [PATCH 3/3] telegram authorizer support --- crates/aide/Cargo.toml | 2 ++ crates/aide/src/axum/inputs.rs | 11 ++++++++++- crates/aide/src/axum/mod.rs | 6 +++--- crates/aide/src/transform.rs | 9 ++++++--- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/crates/aide/Cargo.toml b/crates/aide/Cargo.toml index 24e81e43..a2fc583d 100644 --- a/crates/aide/Cargo.toml +++ b/crates/aide/Cargo.toml @@ -31,6 +31,7 @@ cfg-if = "1.0.0" # custom axum extractors serde_qs = { version = "0.13", optional = true } jwt-authorizer = { version = "0.14", default-features = false, optional = true } +telegram-authorizer = { version = "0.1.0", default-features = false, optional = true } [features] macros = ["dep:aide-macros"] @@ -52,6 +53,7 @@ axum-wasm = ["axum"] serde_qs = ["dep:serde_qs"] jwt-authorizer = ["dep:jwt-authorizer"] +telegram-authorizer = ["dep:telegram-authorizer"] [dev-dependencies] serde = { version = "1.0.144", features = ["derive"] } diff --git a/crates/aide/src/axum/inputs.rs b/crates/aide/src/axum/inputs.rs index d0ad5c73..f6c0414d 100644 --- a/crates/aide/src/axum/inputs.rs +++ b/crates/aide/src/axum/inputs.rs @@ -424,7 +424,7 @@ mod jwt_authorizer { ctx.security_schemes.insert( t.clone(), ReferenceOr::Item(SecurityScheme::Http { - scheme: "Bearer".to_string(), + scheme: "bearer".to_string(), bearer_format: Some("JWT".to_string()), description: Some("A bearer token.".to_string()), extensions: Default::default(), @@ -435,3 +435,12 @@ mod jwt_authorizer { } } } + +#[cfg(feature = "telegram-authorizer")] +mod telegram_authorizer { + + use crate::OperationInput; + use ::telegram_authorizer::TelegramUser; + + impl OperationInput for TelegramUser {} +} diff --git a/crates/aide/src/axum/mod.rs b/crates/aide/src/axum/mod.rs index e7fcbe02..bd4a9838 100644 --- a/crates/aide/src/axum/mod.rs +++ b/crates/aide/src/axum/mod.rs @@ -177,6 +177,8 @@ use crate::{ util::merge_paths, OperationInput, OperationOutput, }; +#[cfg(not(feature = "axum-wasm"))] +use axum::extract::connect_info::IntoMakeServiceWithConnectInfo; use axum::{ body::Body, handler::Handler, @@ -185,8 +187,6 @@ use axum::{ routing::{IntoMakeService, Route, RouterAsService, RouterIntoService}, Router, }; -#[cfg(not(feature = "axum-wasm"))] -use axum::extract::connect_info::IntoMakeServiceWithConnectInfo; use indexmap::map::Entry; use indexmap::IndexMap; use tower_layer::Layer; @@ -361,7 +361,7 @@ where } fn merge_api(&mut self, api: &mut OpenApi) { - self.merge_api_with(api, |x| x) + self.merge_api_with(api, |x| x); } fn merge_api_with(&mut self, api: &mut OpenApi, transform: F) where diff --git a/crates/aide/src/transform.rs b/crates/aide/src/transform.rs index 5e97d495..bb979067 100644 --- a/crates/aide/src/transform.rs +++ b/crates/aide/src/transform.rs @@ -646,7 +646,10 @@ impl<'t> TransformOperation<'t> { { in_context(|ctx| { if let Some(mut res) = R::operation_response(ctx, self.operation) { - let responses = self.operation.responses.get_or_insert_with(Default::default); + let responses = self + .operation + .responses + .get_or_insert_with(Default::default); if responses.default.is_none() { let t = transform(TransformResponse::new(&mut res)); @@ -838,7 +841,7 @@ impl<'t> TransformOperation<'t> { let t = callback_transform(TransformCallback::new(p)); if t.hidden { - callbacks.remove(callback_url); + callbacks.swap_remove(callback_url); if self .operation .callbacks @@ -848,7 +851,7 @@ impl<'t> TransformOperation<'t> { .unwrap() .is_empty() { - self.operation.callbacks.remove(callback_name); + self.operation.callbacks.swap_remove(callback_name); } }