mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-27 09:12:57 +01:00
add optional auth extractor implement. (#205)
This commit is contained in:
parent
477b0f8f06
commit
07deaadd7b
@ -1,6 +1,9 @@
|
||||
# Changes
|
||||
|
||||
## Unreleased - 2021-xx-xx
|
||||
* impl `AuthExtractor` trait for `Option<T: AuthExtractor>` and `Result<T: AuthExtractor, T::Error>`. [#205]
|
||||
|
||||
[#205]: https://github.com/actix/actix-extras/pull/205
|
||||
|
||||
|
||||
## 0.6.0-beta.3 - 2021-10-21
|
||||
|
@ -22,6 +22,7 @@ actix-web = { version = "4.0.0-beta.10", default_features = false }
|
||||
actix-service = "2.0.0"
|
||||
base64 = "0.13"
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
pin-project-lite = "0.2.7"
|
||||
|
||||
[dev-dependencies]
|
||||
actix-cors = "0.6.0-beta.3"
|
||||
|
@ -1,8 +1,15 @@
|
||||
//! Type-safe authentication information extractors
|
||||
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use actix_web::dev::ServiceRequest;
|
||||
use actix_web::Error;
|
||||
use std::future::Future;
|
||||
use futures_util::ready;
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
pub mod basic;
|
||||
pub mod bearer;
|
||||
@ -31,3 +38,66 @@ pub trait AuthExtractor: Sized {
|
||||
/// Parse the authentication credentials from the actix' `ServiceRequest`.
|
||||
fn from_service_request(req: &ServiceRequest) -> Self::Future;
|
||||
}
|
||||
|
||||
impl<T: AuthExtractor> AuthExtractor for Option<T> {
|
||||
type Error = T::Error;
|
||||
|
||||
type Future = AuthExtractorOptFut<T::Future>;
|
||||
|
||||
fn from_service_request(req: &ServiceRequest) -> Self::Future {
|
||||
let fut = T::from_service_request(req);
|
||||
AuthExtractorOptFut { fut }
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
#[doc(hidden)]
|
||||
pub struct AuthExtractorOptFut<F> {
|
||||
#[pin]
|
||||
fut: F
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T, E> Future for AuthExtractorOptFut<F>
|
||||
where
|
||||
F: Future<Output = Result<T, E>>,
|
||||
{
|
||||
type Output = Result<Option<T>, E>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let res = ready!(self.project().fut.poll(cx));
|
||||
Poll::Ready(Ok(res.ok()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AuthExtractor> AuthExtractor for Result<T, T::Error> {
|
||||
type Error = T::Error;
|
||||
|
||||
type Future = AuthExtractorResFut<T::Future>;
|
||||
|
||||
fn from_service_request(req: &ServiceRequest) -> Self::Future {
|
||||
AuthExtractorResFut {
|
||||
fut: T::from_service_request(req),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
#[doc(hidden)]
|
||||
pub struct AuthExtractorResFut<F> {
|
||||
#[pin]
|
||||
fut: F
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T, E> Future for AuthExtractorResFut<F>
|
||||
where
|
||||
F: Future<Output = Result<T, E>>,
|
||||
{
|
||||
type Output = Result<F::Output, E>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let res = ready!(self.project().fut.poll(cx));
|
||||
Poll::Ready(Ok(res))
|
||||
}
|
||||
}
|
||||
|
@ -247,8 +247,8 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::extractors::bearer::BearerAuth;
|
||||
use actix_service::{into_service, Service};
|
||||
use actix_web::error;
|
||||
use actix_web::test::TestRequest;
|
||||
use actix_web::{error, HttpResponse};
|
||||
|
||||
/// This is a test for https://github.com/actix/actix-extras/issues/10
|
||||
#[actix_rt::test]
|
||||
@ -309,4 +309,54 @@ mod tests {
|
||||
assert!(f2.is_err());
|
||||
assert!(f3.is_err());
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_middleware_opt_extractor() {
|
||||
let middleware = AuthenticationMiddleware {
|
||||
service: Rc::new(into_service(|req: ServiceRequest| async move {
|
||||
Ok::<ServiceResponse, _>(req.into_response(HttpResponse::Ok().finish()))
|
||||
})),
|
||||
process_fn: Arc::new(|req, auth: Option<BearerAuth>| {
|
||||
assert!(auth.is_none());
|
||||
async { Ok(req) }
|
||||
}),
|
||||
_extractor: PhantomData,
|
||||
};
|
||||
|
||||
let req = TestRequest::get()
|
||||
.append_header(("Authorization996", "Bearer 1"))
|
||||
.to_srv_request();
|
||||
|
||||
let f = middleware.call(req).await;
|
||||
|
||||
let _res = futures_util::future::lazy(|cx| middleware.poll_ready(cx)).await;
|
||||
|
||||
assert!(f.is_ok());
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_middleware_res_extractor() {
|
||||
let middleware = AuthenticationMiddleware {
|
||||
service: Rc::new(into_service(|req: ServiceRequest| async move {
|
||||
Ok::<ServiceResponse, _>(req.into_response(HttpResponse::Ok().finish()))
|
||||
})),
|
||||
process_fn: Arc::new(
|
||||
|req, auth: Result<BearerAuth, <BearerAuth as AuthExtractor>::Error>| {
|
||||
assert!(auth.is_err());
|
||||
async { Ok(req) }
|
||||
},
|
||||
),
|
||||
_extractor: PhantomData,
|
||||
};
|
||||
|
||||
let req = TestRequest::get()
|
||||
.append_header(("Authorization", "BearerLOL"))
|
||||
.to_srv_request();
|
||||
|
||||
let f = middleware.call(req).await;
|
||||
|
||||
let _res = futures_util::future::lazy(|cx| middleware.poll_ready(cx)).await;
|
||||
|
||||
assert!(f.is_ok());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user