mirror of
https://github.com/TECHNOFAB11/jwt-authorizer.git
synced 2025-12-11 23:50:07 +01:00
feat: implementation of named cookie as jwt source (#10)
* feat: working but naive implementation of named cookie as jwt source * refactor: add with_jwt_source to JwtAuthorizer. Make Bearer default * fix: fix the demo-server. Remove JWTSource * refactor: rename with_jwt_source() -> jwt_source()
This commit is contained in:
parent
783ed7e340
commit
9054f400dc
3 changed files with 76 additions and 11 deletions
29
Cargo.lock
generated
29
Cargo.lock
generated
|
|
@ -178,6 +178,17 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
|
|
@ -740,6 +751,7 @@ dependencies = [
|
|||
"thiserror",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-cookies",
|
||||
"tower-http",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
|
|
@ -1560,6 +1572,23 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-cookies"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40f38d941a2ffd8402b36e02ae407637a9caceb693aaf2edc910437db0f36984"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"cookie",
|
||||
"futures-util",
|
||||
"http",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.4.0"
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ tokio = { version = "1.25", features = ["full"] }
|
|||
tower-http = { version = "0.4", features = ["trace", "auth"] }
|
||||
tower-layer = "0.3"
|
||||
tower-service = "0.3"
|
||||
tower-cookies = "0.9.0"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
|
|
|
|||
|
|
@ -13,12 +13,13 @@ use std::sync::Arc;
|
|||
use std::task::{Context, Poll};
|
||||
use tower_layer::Layer;
|
||||
use tower_service::Service;
|
||||
use tower_cookies::Cookies;
|
||||
|
||||
use crate::authorizer::{Authorizer, FnClaimsChecker, KeySourceType};
|
||||
use crate::error::InitError;
|
||||
use crate::jwks::key_store_manager::Refresh;
|
||||
use crate::validation::Validation;
|
||||
use crate::{AuthError, RefreshStrategy};
|
||||
use crate::{AuthError, layer, RefreshStrategy};
|
||||
|
||||
/// Authorizer Layer builder
|
||||
///
|
||||
|
|
@ -32,6 +33,7 @@ where
|
|||
refresh: Option<Refresh>,
|
||||
claims_checker: Option<FnClaimsChecker<C>>,
|
||||
validation: Option<Validation>,
|
||||
pub jwt_source: JwtSource,
|
||||
}
|
||||
|
||||
/// authorization layer builder
|
||||
|
|
@ -46,6 +48,7 @@ where
|
|||
refresh: Default::default(),
|
||||
claims_checker: None,
|
||||
validation: None,
|
||||
jwt_source: JwtSource::Bearer,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +59,7 @@ where
|
|||
refresh: Default::default(),
|
||||
claims_checker: None,
|
||||
validation: None,
|
||||
jwt_source: JwtSource::Bearer,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,6 +70,7 @@ where
|
|||
refresh: Default::default(),
|
||||
claims_checker: None,
|
||||
validation: None,
|
||||
jwt_source: JwtSource::Bearer,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,6 +91,7 @@ where
|
|||
refresh: Default::default(),
|
||||
claims_checker: None,
|
||||
validation: None,
|
||||
jwt_source: JwtSource::Bearer,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +112,7 @@ where
|
|||
refresh: Default::default(),
|
||||
claims_checker: None,
|
||||
validation: None,
|
||||
jwt_source: JwtSource::Bearer,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,6 +133,7 @@ where
|
|||
refresh: Default::default(),
|
||||
claims_checker: None,
|
||||
validation: None,
|
||||
jwt_source: JwtSource::Bearer,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -164,14 +172,19 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
pub fn jwt_source(mut self, src: JwtSource) -> JwtAuthorizer<C> {
|
||||
self.jwt_source = src;
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Build axum layer
|
||||
pub async fn layer(self) -> Result<AsyncAuthorizationLayer<C>, InitError> {
|
||||
let val = self.validation.unwrap_or_default();
|
||||
let auth = Arc::new(Authorizer::build(&self.key_source_type, self.claims_checker, self.refresh, val).await?);
|
||||
Ok(AsyncAuthorizationLayer::new(auth))
|
||||
Ok(AsyncAuthorizationLayer::new(auth, self.jwt_source))
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for authorizing requests.
|
||||
pub trait AsyncAuthorizer<B> {
|
||||
type RequestBody;
|
||||
|
|
@ -196,10 +209,24 @@ where
|
|||
fn authorize(&self, mut request: Request<B>) -> Self::Future {
|
||||
let authorizer = self.auth.clone();
|
||||
let h = request.headers();
|
||||
let bearer_o: Option<Authorization<Bearer>> = h.typed_get();
|
||||
|
||||
let token = match &self.jwt_source {
|
||||
layer::JwtSource::Bearer => {
|
||||
let bearer_o : Option<Authorization<Bearer>> = h.typed_get();
|
||||
bearer_o.and_then(|b| Some(String::from(b.0.token())))
|
||||
}
|
||||
layer::JwtSource::Cookie(name) => {
|
||||
if let Some(c) = request.extensions().get::<Cookies>() {
|
||||
c.get(name.as_str()).and_then(|c| Some(String::from(c.value())))
|
||||
} else {
|
||||
tracing::warn!("You have to add the tower_cookies::CookieManagerLayer middleware to use Cookies as JWT source.");
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
Box::pin(async move {
|
||||
if let Some(bearer) = bearer_o {
|
||||
match authorizer.check_auth(bearer.token()).await {
|
||||
if let Some(token) = token {
|
||||
match authorizer.check_auth(token.as_str()).await {
|
||||
Ok(token_data) => {
|
||||
// Set `token_data` as a request extension so it can be accessed by other
|
||||
// services down the stack.
|
||||
|
|
@ -224,14 +251,15 @@ where
|
|||
C: Clone + DeserializeOwned + Send,
|
||||
{
|
||||
auth: Arc<Authorizer<C>>,
|
||||
jwt_source: JwtSource,
|
||||
}
|
||||
|
||||
impl<C> AsyncAuthorizationLayer<C>
|
||||
where
|
||||
C: Clone + DeserializeOwned + Send,
|
||||
{
|
||||
pub fn new(auth: Arc<Authorizer<C>>) -> AsyncAuthorizationLayer<C> {
|
||||
Self { auth }
|
||||
pub fn new(auth: Arc<Authorizer<C>>, jwt_source: JwtSource) -> AsyncAuthorizationLayer<C> {
|
||||
Self { auth, jwt_source }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -242,12 +270,18 @@ where
|
|||
type Service = AsyncAuthorizationService<S, C>;
|
||||
|
||||
fn layer(&self, inner: S) -> Self::Service {
|
||||
AsyncAuthorizationService::new(inner, self.auth.clone())
|
||||
AsyncAuthorizationService::new(inner, self.auth.clone(), self.jwt_source.clone())
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- AsyncAuthorizationService --------
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum JwtSource{
|
||||
Bearer,
|
||||
Cookie(String),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AsyncAuthorizationService<S, C>
|
||||
where
|
||||
|
|
@ -255,6 +289,7 @@ where
|
|||
{
|
||||
pub inner: S,
|
||||
pub auth: Arc<Authorizer<C>>,
|
||||
pub jwt_source: JwtSource,
|
||||
}
|
||||
|
||||
impl<S, C> AsyncAuthorizationService<S, C>
|
||||
|
|
@ -283,8 +318,8 @@ where
|
|||
/// Authorize requests using a custom scheme.
|
||||
///
|
||||
/// The `Authorization` header is required to have the value provided.
|
||||
pub fn new(inner: S, auth: Arc<Authorizer<C>>) -> AsyncAuthorizationService<S, C> {
|
||||
Self { inner, auth }
|
||||
pub fn new(inner: S, auth: Arc<Authorizer<C>>, jwt_source: JwtSource) -> AsyncAuthorizationService<S, C> {
|
||||
Self { inner, auth , jwt_source }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue