mirror of
https://github.com/TECHNOFAB11/jwt-authorizer.git
synced 2025-12-12 08:00:07 +01:00
feat: multiple auths per AsyncAuthorizationService
This commit is contained in:
parent
27cce24372
commit
57fbc6e399
2 changed files with 38 additions and 14 deletions
|
|
@ -55,6 +55,9 @@ pub enum AuthError {
|
|||
|
||||
#[error("Invalid Claim")]
|
||||
InvalidClaims(),
|
||||
|
||||
#[error("No Authorizer")]
|
||||
NoAuthorizer(),
|
||||
}
|
||||
|
||||
fn response_wwwauth(status: StatusCode, bearer: &str) -> Response<BoxBody> {
|
||||
|
|
@ -166,6 +169,10 @@ impl IntoResponse for AuthError {
|
|||
debug!("AuthErrors::InvalidClaims");
|
||||
response_wwwauth(StatusCode::FORBIDDEN, "error=\"insufficient_scope\"")
|
||||
}
|
||||
AuthError::NoAuthorizer() => {
|
||||
debug!("AuthErrors::NoAuthorizer");
|
||||
response_wwwauth(StatusCode::FORBIDDEN, "error=\"invalid_token\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use futures_core::ready;
|
|||
use futures_util::future::BoxFuture;
|
||||
use headers::authorization::Bearer;
|
||||
use headers::{Authorization, HeaderMapExt};
|
||||
use jsonwebtoken::TokenData;
|
||||
use pin_project::pin_project;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::future::Future;
|
||||
|
|
@ -209,10 +210,9 @@ where
|
|||
type Future = BoxFuture<'static, Result<Request<B>, AuthError>>;
|
||||
|
||||
fn authorize(&self, mut request: Request<B>) -> Self::Future {
|
||||
let authorizer = self.auth.clone();
|
||||
// TODO: extract token per authorizer (jwt_source shloud be per authorizer)
|
||||
let h = request.headers();
|
||||
|
||||
let token = match &self.jwt_source {
|
||||
let token_o = match &self.jwt_source {
|
||||
layer::JwtSource::AuthorizationHeader => {
|
||||
let bearer_o: Option<Authorization<Bearer>> = h.typed_get();
|
||||
bearer_o.map(|b| String::from(b.0.token()))
|
||||
|
|
@ -221,17 +221,30 @@ where
|
|||
.typed_get::<headers::Cookie>()
|
||||
.and_then(|c| c.get(name.as_str()).map(String::from)),
|
||||
};
|
||||
|
||||
let authorizers: Vec<Arc<Authorizer<C>>> = self.auths.iter().map(|a| a.clone()).collect();
|
||||
|
||||
Box::pin(async move {
|
||||
if let Some(token) = token {
|
||||
authorizer.check_auth(token.as_str()).await.map(|token_data| {
|
||||
if let Some(token) = token_o {
|
||||
let mut token_data: Result<TokenData<C>, AuthError> = Err(AuthError::NoAuthorizer());
|
||||
for auth in authorizers {
|
||||
token_data = auth.check_auth(token.as_str()).await;
|
||||
if token_data.is_ok() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
match token_data {
|
||||
Ok(tdata) => {
|
||||
// Set `token_data` as a request extension so it can be accessed by other
|
||||
// services down the stack.
|
||||
request.extensions_mut().insert(token_data);
|
||||
request.extensions_mut().insert(tdata);
|
||||
|
||||
request
|
||||
})
|
||||
return Ok(request);
|
||||
}
|
||||
Err(err) => return Err(err), // TODO: error containing all errors (not just the last one)
|
||||
}
|
||||
} else {
|
||||
Err(AuthError::MissingToken())
|
||||
return Err(AuthError::MissingToken());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -291,7 +304,7 @@ where
|
|||
C: Clone + DeserializeOwned + Send + Sync,
|
||||
{
|
||||
pub inner: S,
|
||||
pub auth: Arc<Authorizer<C>>,
|
||||
pub auths: Vec<Arc<Authorizer<C>>>,
|
||||
pub jwt_source: JwtSource,
|
||||
}
|
||||
|
||||
|
|
@ -322,7 +335,11 @@ where
|
|||
///
|
||||
/// The `Authorization` header is required to have the value provided.
|
||||
pub fn new(inner: S, auth: Arc<Authorizer<C>>, jwt_source: JwtSource) -> AsyncAuthorizationService<S, C> {
|
||||
Self { inner, auth, jwt_source }
|
||||
Self {
|
||||
inner,
|
||||
auths: vec![auth],
|
||||
jwt_source,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue