Skip to content

Commit d7d1c64

Browse files
committed
refactor: use static fut auth layer
1 parent 7b8ae15 commit d7d1c64

File tree

4 files changed

+108
-199
lines changed

4 files changed

+108
-199
lines changed

syndapi/src/serve/auth.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use tracing::warn;
77
use crate::{
88
client::github::GithubClient,
99
principal::{Principal, User},
10-
serve::layer::authenticate::v2::Authenticate,
10+
serve::layer::authenticate::Authenticate,
1111
};
1212

1313
#[derive(Clone)]

syndapi/src/serve/layer/authenticate/mod.rs

+106-57
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,99 @@
1-
pub mod v2;
2-
// testing v2 impl...
3-
/*
4-
use std::task::{Context, Poll};
5-
6-
use axum::http::{self, StatusCode};
7-
use axum::response::IntoResponse;
8-
use futures_util::future::BoxFuture;
1+
use std::{
2+
convert::Infallible,
3+
future::Future,
4+
pin::Pin,
5+
task::{Context, Poll},
6+
};
7+
8+
use axum::{
9+
extract::Request,
10+
http::StatusCode,
11+
response::{IntoResponse, Response},
12+
};
13+
use pin_project::pin_project;
914
use tower::{Layer, Service};
1015

11-
use crate::serve::auth::Authenticator;
16+
use crate::principal::Principal;
1217

18+
pub trait Authenticate {
19+
// how to implementor fill this associate type
20+
// need impl trait in associate type ?
21+
// https://github.com/rust-lang/rust/issues/63063
22+
type Output: Future<Output = Result<Principal, ()>>;
23+
24+
fn authenticate(&self, token: Option<String>) -> Self::Output;
25+
}
26+
27+
#[pin_project(project = AuthFutureProj)]
28+
pub enum AuthenticateFuture<AuthFut, S, F> {
29+
Authenticate {
30+
req: Option<Request>,
31+
#[pin]
32+
auth_fut: AuthFut,
33+
inner: S,
34+
},
35+
ServiceCall {
36+
#[pin]
37+
service_fut: F,
38+
},
39+
}
40+
41+
impl<AuthFut, S, F> AuthenticateFuture<AuthFut, S, F> {
42+
fn new(req: Request, auth_fut: AuthFut, inner: S) -> Self {
43+
AuthenticateFuture::Authenticate {
44+
req: Some(req),
45+
auth_fut,
46+
inner,
47+
}
48+
}
49+
}
50+
51+
impl<AuthFut, S> Future for AuthenticateFuture<AuthFut, S, S::Future>
52+
where
53+
AuthFut: Future<Output = Result<Principal, ()>>,
54+
S: Service<Request, Response = Response, Error = Infallible>,
55+
{
56+
type Output = Result<Response, Infallible>;
57+
58+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
59+
match self.as_mut().project() {
60+
AuthFutureProj::Authenticate {
61+
req,
62+
auth_fut,
63+
inner,
64+
} => match auth_fut.poll(cx) {
65+
Poll::Ready(Ok(principal)) => {
66+
let mut req = req.take().unwrap();
67+
req.extensions_mut().insert(principal);
68+
let service_fut = inner.call(req);
69+
70+
self.set(AuthenticateFuture::ServiceCall { service_fut });
71+
self.poll(cx)
72+
}
73+
Poll::Ready(Err(_)) => Poll::Ready(Ok(StatusCode::UNAUTHORIZED.into_response())),
74+
Poll::Pending => Poll::Pending,
75+
},
76+
AuthFutureProj::ServiceCall { service_fut } => service_fut.poll(cx),
77+
}
78+
}
79+
}
1380

1481
#[derive(Clone)]
15-
pub struct AuthenticateLayer {
16-
authenticator: Authenticator,
82+
pub struct AuthenticateLayer<A> {
83+
authenticator: A,
1784
}
1885

19-
impl AuthenticateLayer {
20-
pub fn new(authenticator: Authenticator) -> Self {
86+
impl<A> AuthenticateLayer<A> {
87+
pub fn new(authenticator: A) -> Self {
2188
Self { authenticator }
2289
}
2390
}
2491

25-
impl<S> Layer<S> for AuthenticateLayer {
26-
type Service = AuthenticateService<S>;
92+
impl<S, A> Layer<S> for AuthenticateLayer<A>
93+
where
94+
A: Authenticate + Clone,
95+
{
96+
type Service = AuthenticateService<S, A>;
2797

2898
fn layer(&self, inner: S) -> Self::Service {
2999
AuthenticateService {
@@ -34,58 +104,37 @@ impl<S> Layer<S> for AuthenticateLayer {
34104
}
35105

36106
#[derive(Clone)]
37-
pub struct AuthenticateService<S> {
38-
authenticator: Authenticator,
107+
pub struct AuthenticateService<S, A> {
39108
inner: S,
109+
authenticator: A,
40110
}
41111

42-
impl<S> Service<axum::extract::Request> for AuthenticateService<S>
112+
impl<S, A> Service<Request> for AuthenticateService<S, A>
43113
where
44-
S: Service<axum::extract::Request, Response = axum::response::Response>
45-
+ Send
46-
+ 'static
47-
+ Clone,
48-
S::Future: Send + 'static,
114+
S: Service<Request, Response = Response, Error = Infallible> + Clone,
115+
A: Authenticate,
49116
{
50-
type Response = S::Response;
51-
52-
type Error = S::Error;
53-
54-
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
55-
56-
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
117+
type Response = Response;
118+
type Error = Infallible;
119+
type Future = AuthenticateFuture<A::Output, S, S::Future>;
120+
121+
fn poll_ready(
122+
&mut self,
123+
cx: &mut std::task::Context<'_>,
124+
) -> std::task::Poll<Result<(), Self::Error>> {
57125
self.inner.poll_ready(cx)
58126
}
59127

60-
fn call(&mut self, mut request: axum::extract::Request) -> Self::Future {
61-
let header = request
128+
fn call(&mut self, req: Request) -> Self::Future {
129+
let token = req
62130
.headers()
63-
.get(http::header::AUTHORIZATION)
64-
.and_then(|header| header.to_str().ok());
65-
66-
let Some(token) = header else {
67-
return Box::pin(async { Ok(StatusCode::UNAUTHORIZED.into_response()) });
68-
};
69-
70-
let Self {
71-
authenticator,
72-
mut inner,
73-
} = self.clone();
74-
let token = token.to_owned();
75-
76-
Box::pin(async move {
77-
let principal = match authenticator.authenticate(Some(token)).await {
78-
Ok(principal) => principal,
79-
Err(_) => {
80-
tracing::warn!("Invalid token");
81-
return Ok(StatusCode::UNAUTHORIZED.into_response());
82-
}
83-
};
131+
.get(axum::http::header::AUTHORIZATION)
132+
.and_then(|header| header.to_str().ok())
133+
.map(ToOwned::to_owned);
84134

85-
request.extensions_mut().insert(principal);
135+
let auth_fut = self.authenticator.authenticate(token);
136+
let inner = self.inner.clone();
86137

87-
inner.call(request).await
88-
})
138+
AuthenticateFuture::new(req, auth_fut, inner)
89139
}
90140
}
91-
*/

syndapi/src/serve/layer/authenticate/v2.rs

-140
This file was deleted.

syndapi/src/serve/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub async fn serve(listener: TcpListener, dep: Dependency) -> anyhow::Result<()>
4848
let service = Router::new()
4949
.route("/graphql", post(gql::handler::graphql))
5050
.layer(Extension(schema))
51-
.layer(authenticate::v2::AuthenticateLayer::new(authenticator))
51+
.layer(authenticate::AuthenticateLayer::new(authenticator))
5252
.route("/graphql", get(gql::handler::graphiql))
5353
.layer(
5454
ServiceBuilder::new()

0 commit comments

Comments
 (0)