use lazy_static::lazy_static; use okapi::openapi3::{Object, SecurityRequirement, SecurityScheme, SecuritySchemeData}; use rocket::{ http::Status, request::{self, FromRequest}, Request, }; use rocket_okapi::{ gen::OpenApiGenerator, request::{OpenApiFromRequest, RequestHeaderInput}, }; lazy_static! { static ref API_KEYS: Vec = { serde_json::from_str( &std::fs::read_to_string("api_keys.json").expect("api_keys.json does not exist"), ) .expect("api_keys.json is not valid") }; } #[derive(Clone, Copy, Debug)] pub struct ApiKey; #[rocket::async_trait] impl<'r> FromRequest<'r> for ApiKey { type Error = ApiKey; async fn from_request(req: &'r Request<'_>) -> request::Outcome { if req .headers() .get("X-API-Key") .any(|k| API_KEYS.contains(&String::from(k))) { request::Outcome::Success(ApiKey) } else { request::Outcome::Failure((Status::Unauthorized, ApiKey)) } } } impl<'a> OpenApiFromRequest<'a> for ApiKey { fn from_request_input( _gen: &mut OpenApiGenerator, _name: String, _required: bool, ) -> rocket_okapi::Result { // Setup global requirement for Security scheme let security_scheme = SecurityScheme { description: Some("Requires an API key to access".to_owned()), // Setup data requirements. // This can be part of the `header`, `query` or `cookie`. // In this case the header `x-api-key: mykey` needs to be set. data: SecuritySchemeData::ApiKey { name: "x-api-key".to_owned(), location: "header".to_owned(), }, extensions: Object::default(), }; // Add the requirement for this route/endpoint // This can change between routes. let mut security_req = SecurityRequirement::new(); // Each security requirement needs to be met before access is allowed. security_req.insert("ApiKeyAuth".to_owned(), Vec::new()); // These vvvvvvv-----^^^^^^^^^^ values need to match exactly! Ok(RequestHeaderInput::Security( "ApiKeyAuth".to_owned(), security_scheme, security_req, )) } }