Fix the Swagger UI not working when MAS is mounted on a prefix (#4515)

This commit is contained in:
Quentin Gliech
2025-05-07 14:57:27 +02:00
committed by GitHub
3 changed files with 74 additions and 33 deletions
+57 -28
View File
@@ -81,35 +81,61 @@ fn finish(t: TransformOpenApi) -> TransformOpenApi {
),
..Default::default()
})
.security_scheme("oauth2", oauth_security_scheme(None))
.security_scheme(
"oauth2",
SecurityScheme::OAuth2 {
flows: OAuth2Flows {
client_credentials: Some(OAuth2Flow::ClientCredentials {
refresh_url: Some(OAuth2TokenEndpoint::PATH.to_owned()),
token_url: OAuth2TokenEndpoint::PATH.to_owned(),
scopes: IndexMap::from([(
"urn:mas:admin".to_owned(),
"Grant access to the admin API".to_owned(),
)]),
}),
authorization_code: Some(OAuth2Flow::AuthorizationCode {
authorization_url: OAuth2AuthorizationEndpoint::PATH.to_owned(),
refresh_url: Some(OAuth2TokenEndpoint::PATH.to_owned()),
token_url: OAuth2TokenEndpoint::PATH.to_owned(),
scopes: IndexMap::from([(
"urn:mas:admin".to_owned(),
"Grant access to the admin API".to_owned(),
)]),
}),
implicit: None,
password: None,
},
description: None,
"token",
SecurityScheme::Http {
scheme: "bearer".to_owned(),
bearer_format: None,
description: Some("An access token with access to the admin API".to_owned()),
extensions: IndexMap::default(),
},
)
.security_requirement_scopes("oauth2", ["urn:mas:admin"])
.security_requirement_scopes("bearer", ["urn:mas:admin"])
}
fn oauth_security_scheme(url_builder: Option<&UrlBuilder>) -> SecurityScheme {
let (authorization_url, token_url) = if let Some(url_builder) = url_builder {
(
url_builder.oauth_authorization_endpoint().to_string(),
url_builder.oauth_token_endpoint().to_string(),
)
} else {
// This is a dirty fix for Swagger UI: when it joins the URLs with the
// base URL, if the path starts with a slash, it will go to the root of
// the domain instead of the API root.
// It works if we make it explicitly relative
(
format!(".{}", OAuth2AuthorizationEndpoint::PATH),
format!(".{}", OAuth2TokenEndpoint::PATH),
)
};
let scopes = IndexMap::from([(
"urn:mas:admin".to_owned(),
"Grant access to the admin API".to_owned(),
)]);
SecurityScheme::OAuth2 {
flows: OAuth2Flows {
client_credentials: Some(OAuth2Flow::ClientCredentials {
refresh_url: Some(token_url.clone()),
token_url: token_url.clone(),
scopes: scopes.clone(),
}),
authorization_code: Some(OAuth2Flow::AuthorizationCode {
authorization_url,
refresh_url: Some(token_url.clone()),
token_url,
scopes,
}),
implicit: None,
password: None,
},
description: None,
extensions: IndexMap::default(),
}
}
pub fn router<S>() -> (OpenApi, Router<S>)
@@ -146,10 +172,13 @@ where
move |State(url_builder): State<UrlBuilder>| {
// Let's set the servers to the HTTP base URL
let mut api = api.clone();
api.servers = vec![Server {
url: url_builder.http_base().to_string(),
..Server::default()
}];
let _ = TransformOpenApi::new(&mut api)
.server(Server {
url: url_builder.http_base().to_string(),
..Server::default()
})
.security_scheme("oauth2", oauth_security_scheme(Some(&url_builder)));
std::future::ready(Json(api))
}
+2
View File
@@ -249,6 +249,8 @@ where
ACCEPT_LANGUAGE,
CONTENT_LANGUAGE,
CONTENT_TYPE,
// Swagger will send this header, so we have to allow it to avoid CORS errors
HeaderName::from_static("x-requested-with"),
])
.max_age(Duration::from_secs(60 * 60)),
)
+15 -5
View File
@@ -2527,21 +2527,26 @@
"type": "oauth2",
"flows": {
"clientCredentials": {
"refreshUrl": "/oauth2/token",
"tokenUrl": "/oauth2/token",
"refreshUrl": "./oauth2/token",
"tokenUrl": "./oauth2/token",
"scopes": {
"urn:mas:admin": "Grant access to the admin API"
}
},
"authorizationCode": {
"authorizationUrl": "/authorize",
"tokenUrl": "/oauth2/token",
"refreshUrl": "/oauth2/token",
"authorizationUrl": "./authorize",
"tokenUrl": "./oauth2/token",
"refreshUrl": "./oauth2/token",
"scopes": {
"urn:mas:admin": "Grant access to the admin API"
}
}
}
},
"token": {
"type": "http",
"scheme": "bearer",
"description": "An access token with access to the admin API"
}
},
"schemas": {
@@ -3725,6 +3730,11 @@
"oauth2": [
"urn:mas:admin"
]
},
{
"bearer": [
"urn:mas:admin"
]
}
],
"tags": [