Skip to content

Commit 73c9c8b

Browse files
feat: add method session (#189)
1 parent 422e40f commit 73c9c8b

38 files changed

Lines changed: 527 additions & 323 deletions

File tree

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ jobs:
5858
message: ${{ steps.extract-version.outputs.VERSION }}
5959
token: ${{ steps.app-token.outputs.token }}
6060

61+
- name: Reset and pull
62+
run: git reset --hard && git pull
63+
6164
- name: Tag
6265
uses: bruno-fs/repo-tagger@1.0.0
6366
with:

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/dioxus-axum/src/main.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ async fn main() {
2424
};
2525
use shield::{ErasedMethod, Method, Shield, ShieldOptions};
2626
use shield_bootstrap::BootstrapDioxusStyle;
27-
use shield_dioxus_axum::{AxumDioxusIntegration, ShieldLayer};
27+
use shield_dioxus_axum::{AuthRoutes, AxumDioxusIntegration, ShieldLayer};
2828
use shield_memory::{MemoryStorage, User};
2929
use shield_oidc::{Keycloak, OidcMethod};
3030
use tokio::net::TcpListener;
@@ -45,7 +45,7 @@ async fn main() {
4545
let storage = MemoryStorage::new();
4646
let shield = Shield::new(
4747
storage.clone(),
48-
vec![
48+
vec![Arc::new(
4949
OidcMethod::new(storage).with_providers([Keycloak::builder(
5050
"keycloak",
5151
"http://localhost:18080/realms/Shield",
@@ -59,13 +59,14 @@ async fn main() {
5959
.unwrap_or_else(|| addr.port())
6060
))
6161
.build()]),
62-
],
62+
)],
6363
ShieldOptions::default(),
6464
);
6565
let shield_layer = ShieldLayer::new(shield.clone());
6666

6767
// Initialize router
6868
let router = Router::new()
69+
.nest("/api/auth", AuthRoutes::router::<User, ()>())
6970
.serve_dioxus_application(
7071
ServeConfig::builder()
7172
.context(AxumDioxusIntegration::<User>::default().context())

examples/leptos-axum/src/app.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use leptos::prelude::*;
22
use leptos_meta::{MetaTags, Title, provide_meta_context};
33
use leptos_router::{
4-
components::{Outlet, ParentRoute, Router, Routes},
4+
components::{Outlet, ParentRoute, Route, Router, Routes},
55
path,
66
};
77
use shield_leptos::ShieldRouter;
88

9-
// use crate::home::HomePage;
9+
use crate::home::HomePage;
1010

1111
pub fn shell(options: LeptosOptions) -> impl IntoView {
1212
view! {
@@ -44,7 +44,7 @@ pub fn App() -> impl IntoView {
4444
<Router>
4545
<main>
4646
<Routes fallback=|| "Not found.".into_view()>
47-
// <Route path=path!("") view=HomePage />
47+
<Route path=path!("") view=HomePage />
4848

4949
<ParentRoute path=path!("auth") view=Outlet>
5050
<ShieldRouter />

examples/leptos-axum/src/home.rs

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
use leptos::{either::Either, prelude::*};
2-
use leptos_router::components::A;
1+
use leptos::{
2+
// either::Either,
3+
prelude::*,
4+
};
5+
// use leptos_router::components::A;
36
use shield_leptos::LeptosUser;
47

58
#[server]
@@ -11,31 +14,31 @@ pub async fn user() -> Result<Option<LeptosUser>, ServerFnError> {
1114

1215
#[component]
1316
pub fn HomePage() -> impl IntoView {
14-
let user = OnceResource::new(user());
17+
// let user = OnceResource::new(user());
1518

1619
view! {
1720
<h1>"Shield Leptos Axum Example"</h1>
1821

19-
<Suspense fallback=|| view! { "Loading..." }>
20-
{move || Suspend::new(async move { match user.await {
21-
Ok(user) => Either::Left(match user {
22-
Some(user) => Either::Left(view! {
23-
<p><b>User ID:</b> {user.id}</p>
22+
// <Suspense fallback=|| view! { "Loading..." }>
23+
// {move || Suspend::new(async move { match user.await {
24+
// Ok(user) => Either::Left(match user {
25+
// Some(user) => Either::Left(view! {
26+
// <p><b>User ID:</b> {user.id}</p>
2427

25-
<A href="/auth/sign-out">
26-
<button>"Sign out"</button>
27-
</A>
28-
}),
29-
None => Either::Right(view! {
30-
<A href="/auth/sign-in">
31-
<button>"Sign in"</button>
32-
</A>
33-
}),
34-
}),
35-
Err(err) => Either::Right(view! {
36-
{err.to_string()}
37-
})
38-
}})}
39-
</Suspense>
28+
// <A href="/auth/sign-out">
29+
// <button>"Sign out"</button>
30+
// </A>
31+
// }),
32+
// None => Either::Right(view! {
33+
// <A href="/auth/sign-in">
34+
// <button>"Sign in"</button>
35+
// </A>
36+
// }),
37+
// }),
38+
// Err(err) => Either::Right(view! {
39+
// {err.to_string()}
40+
// })
41+
// }})}
42+
// </Suspense>
4043
}
4144
}

packages/core/shield/src/action.rs

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ use async_trait::async_trait;
44
use serde::{Deserialize, Serialize};
55

66
use crate::{
7-
error::ShieldError, form::Form, provider::Provider, request::Request, response::Response,
8-
session::Session,
7+
error::ShieldError,
8+
form::Form,
9+
provider::Provider,
10+
request::Request,
11+
response::Response,
12+
session::{BaseSession, MethodSession},
913
};
1014

1115
// TODO: Think of a better name.
@@ -31,12 +35,12 @@ pub struct ActionProviderForm {
3135
}
3236

3337
#[async_trait]
34-
pub trait Action<P: Provider>: ErasedAction + Send + Sync {
38+
pub trait Action<P: Provider, S>: ErasedAction + Send + Sync {
3539
fn id(&self) -> String;
3640

3741
fn name(&self) -> String;
3842

39-
fn condition(&self, _provider: &P, _session: Session) -> Result<bool, ShieldError> {
43+
fn condition(&self, _provider: &P, _session: &MethodSession<S>) -> Result<bool, ShieldError> {
4044
Ok(true)
4145
}
4246

@@ -45,7 +49,7 @@ pub trait Action<P: Provider>: ErasedAction + Send + Sync {
4549
async fn call(
4650
&self,
4751
provider: P,
48-
session: Session,
52+
session: &MethodSession<S>,
4953
request: Request,
5054
) -> Result<Response, ShieldError>;
5155
}
@@ -59,7 +63,8 @@ pub trait ErasedAction: Send + Sync {
5963
fn erased_condition(
6064
&self,
6165
provider: &(dyn Any + Send + Sync),
62-
session: Session,
66+
base_session: &BaseSession,
67+
method_session: &(dyn Any + Send + Sync),
6368
) -> Result<bool, ShieldError>;
6469

6570
async fn erased_forms(
@@ -70,7 +75,8 @@ pub trait ErasedAction: Send + Sync {
7075
async fn erased_call(
7176
&self,
7277
provider: Box<dyn Any + Send + Sync>,
73-
session: Session,
78+
base_session: &BaseSession,
79+
method_session: &(dyn Any + Send + Sync),
7480
request: Request,
7581
) -> Result<Response, ShieldError>;
7682
}
@@ -88,21 +94,44 @@ macro_rules! erased_action {
8894
self.name()
8995
}
9096

91-
fn erased_condition(&self, provider: &(dyn std::any::Any + Send + Sync), session: $crate::Session) -> Result<bool, $crate::ShieldError> {
92-
self.condition(provider.downcast_ref().expect("TODO"), session)
97+
fn erased_condition(
98+
&self,
99+
provider: &(dyn std::any::Any + Send + Sync),
100+
base_session: &$crate::BaseSession,
101+
method_session: &(dyn std::any::Any + Send + Sync)
102+
) -> Result<bool, $crate::ShieldError> {
103+
self.condition(
104+
provider.downcast_ref().expect("Provider should be downcast"),
105+
&MethodSession {
106+
base: base_session,
107+
method: method_session.downcast_ref().expect("Session should be downcast"),
108+
},
109+
)
93110
}
94111

95-
async fn erased_forms(&self, provider: Box<dyn std::any::Any + Send + Sync>) -> Result<Vec<$crate::Form>, $crate::ShieldError> {
96-
self.forms(*provider.downcast().expect("TODO")).await
112+
async fn erased_forms(
113+
&self,
114+
provider: Box<dyn std::any::Any + Send + Sync>
115+
) -> Result<Vec<$crate::Form>, $crate::ShieldError> {
116+
self.forms(*provider.downcast().expect("Provider should be downcast")).await
97117
}
98118

99119
async fn erased_call(
100120
&self,
101121
provider: Box<dyn std::any::Any + Send + Sync>,
102-
session: $crate::Session,
122+
base_session: &$crate::BaseSession,
123+
method_session: &(dyn std::any::Any + Send + Sync),
103124
request: $crate::Request,
104125
) -> Result<$crate::Response, $crate::ShieldError> {
105-
self.call(*provider.downcast().expect("TODO"), session, request)
126+
self
127+
.call(
128+
*provider.downcast().expect("Provider should be downcast"),
129+
&$crate::MethodSession {
130+
base: base_session,
131+
method: method_session.downcast_ref().expect("Session should be downcast"),
132+
},
133+
request
134+
)
106135
.await
107136
}
108137
}

packages/core/shield/src/actions/sign_in_callback.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Provider, Session, ShieldError};
1+
use crate::{MethodSession, Provider, ShieldError};
22

33
const ACTION_ID: &str = "sign-in-callback";
44
const ACTION_NAME: &str = "Sign in callback";
@@ -14,7 +14,10 @@ impl SignInCallbackAction {
1414
ACTION_NAME.to_owned()
1515
}
1616

17-
pub fn condition<P: Provider>(_provider: &P, _session: Session) -> Result<bool, ShieldError> {
17+
pub fn condition<P: Provider, S>(
18+
_provider: &P,
19+
_session: &MethodSession<S>,
20+
) -> Result<bool, ShieldError> {
1821
Ok(true)
1922
}
2023
}

packages/core/shield/src/actions/sign_out.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use crate::{
2-
Form, Input, InputType, InputTypeSubmit, Provider, Session, SessionError, ShieldError,
3-
};
1+
use crate::{Form, Input, InputType, InputTypeSubmit, MethodSession, Provider, ShieldError};
42

53
const ACTION_ID: &str = "sign-out";
64
const ACTION_NAME: &str = "Sign out";
@@ -16,13 +14,12 @@ impl SignOutAction {
1614
ACTION_NAME.to_owned()
1715
}
1816

19-
pub fn condition<P: Provider>(provider: &P, session: Session) -> Result<bool, ShieldError> {
20-
let session_data = session.data();
21-
let session_data = session_data
22-
.lock()
23-
.map_err(|err| SessionError::Lock(err.to_string()))?;
24-
25-
Ok(session_data
17+
pub fn condition<P: Provider, S>(
18+
provider: &P,
19+
session: &MethodSession<S>,
20+
) -> Result<bool, ShieldError> {
21+
Ok(session
22+
.base
2623
.authentication
2724
.as_ref()
2825
.is_some_and(|authentication| {

packages/core/shield/src/method.rs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,39 @@
11
use std::any::Any;
22

33
use async_trait::async_trait;
4+
use serde::{Serialize, de::DeserializeOwned};
45

5-
use crate::{ErasedAction, action::Action, error::ShieldError, provider::Provider};
6+
use crate::{
7+
ErasedAction,
8+
action::Action,
9+
error::{SessionError, ShieldError},
10+
provider::Provider,
11+
};
612

713
#[async_trait]
8-
pub trait Method<P: Provider>: Send + Sync {
14+
pub trait Method: Send + Sync {
15+
type Provider: Provider;
16+
type Session: DeserializeOwned + Serialize;
17+
918
fn id(&self) -> String;
1019

11-
fn actions(&self) -> Vec<Box<dyn Action<P>>>;
20+
fn actions(&self) -> Vec<Box<dyn Action<Self::Provider, Self::Session>>>;
1221

13-
fn action_by_id(&self, action_id: &str) -> Option<Box<dyn Action<P>>> {
22+
fn action_by_id(
23+
&self,
24+
action_id: &str,
25+
) -> Option<Box<dyn Action<Self::Provider, Self::Session>>> {
1426
self.actions()
1527
.into_iter()
1628
.find(|action| action.id() == action_id)
1729
}
1830

19-
async fn providers(&self) -> Result<Vec<P>, ShieldError>;
31+
async fn providers(&self) -> Result<Vec<Self::Provider>, ShieldError>;
2032

21-
async fn provider_by_id(&self, provider_id: Option<&str>) -> Result<Option<P>, ShieldError> {
33+
async fn provider_by_id(
34+
&self,
35+
provider_id: Option<&str>,
36+
) -> Result<Option<Self::Provider>, ShieldError> {
2237
Ok(self
2338
.providers()
2439
.await?
@@ -43,6 +58,11 @@ pub trait ErasedMethod: Send + Sync {
4358
&self,
4459
provider_id: Option<&str>,
4560
) -> Result<Option<Box<dyn Any + Send + Sync>>, ShieldError>;
61+
62+
fn erased_deserialize_session(
63+
&self,
64+
value: Option<&str>,
65+
) -> Result<Box<dyn Any + Send + Sync>, SessionError>;
4666
}
4767

4868
#[macro_export]
@@ -71,7 +91,7 @@ macro_rules! erased_method {
7191

7292
async fn erased_providers(
7393
&self,
74-
) -> Result<Vec<(Option<String>, Box<dyn std::any::Any + Send + Sync>)>, ShieldError> {
94+
) -> Result<Vec<(Option<String>, Box<dyn std::any::Any + Send + Sync>)>, $crate::ShieldError> {
7595
self.providers().await.map(|providers| {
7696
providers
7797
.into_iter()
@@ -83,12 +103,27 @@ macro_rules! erased_method {
83103
async fn erased_provider_by_id(
84104
&self,
85105
provider_id: Option<&str>,
86-
) -> Result<Option<Box<dyn std::any::Any + Send + Sync>>, ShieldError> {
106+
) -> Result<Option<Box<dyn std::any::Any + Send + Sync>>, $crate::ShieldError> {
87107
self.provider_by_id(provider_id).await.map(|provider| {
88108
provider
89109
.map(|provider| Box::new(provider) as Box<dyn std::any::Any + Send + Sync>)
90110
})
91111
}
112+
113+
fn erased_deserialize_session(
114+
&self,
115+
value: Option<&str>
116+
) -> Result<Box<dyn std::any::Any + Send + Sync>, $crate::SessionError> {
117+
type Session $( < $( $generic_name ),+ > )* = <$method $( < $( $generic_name ),+ > )* as $crate::Method>::Session;
118+
119+
let session = match value {
120+
Some(value) => serde_json::from_str::<Session $( < $( $generic_name ),+ > )* >(value)
121+
.map_err(|err| $crate::SessionError::Serialization(err.to_string()))?,
122+
None => Session $( ::< $( $generic_name ),+ > )* ::default()
123+
};
124+
125+
Ok(Box::new(session) as Box<dyn std::any::Any + Send + Sync>)
126+
}
92127
}
93128
};
94129
}

0 commit comments

Comments
 (0)