Skip to content

Commit 3d15389

Browse files
feat(dioxus): improve Dioxus example
1 parent 0949481 commit 3d15389

6 files changed

Lines changed: 145 additions & 83 deletions

File tree

Cargo.lock

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

examples/dioxus-axum/Cargo.toml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ server = [
1919
"dep:shield-email",
2020
"dep:shield-memory",
2121
"dep:shield-oidc",
22-
"dep:tokio",
2322
"dep:tower-sessions",
2423
"dioxus/server",
2524
"shield-dioxus/server",
@@ -31,6 +30,7 @@ web = ["dioxus/web"]
3130
[dependencies]
3231
axum = { workspace = true, optional = true }
3332
dioxus = { workspace = true, features = ["fullstack", "router"] }
33+
serde.workspace = true
3434
shield.workspace = true
3535
shield-bootstrap = { workspace = true, features = ["dioxus"] }
3636
shield-dioxus.workspace = true
@@ -40,9 +40,4 @@ shield-email = { workspace = true, features = [
4040
], optional = true }
4141
shield-memory = { workspace = true, optional = true }
4242
shield-oidc = { workspace = true, optional = true }
43-
tokio = { workspace = true, features = [
44-
"macros",
45-
"rt-multi-thread",
46-
], optional = true }
4743
tower-sessions = { workspace = true, optional = true }
48-
tracing.workspace = true

examples/dioxus-axum/src/api.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use dioxus::prelude::*;
2+
use serde::{Deserialize, Serialize};
3+
#[cfg(feature = "server")]
4+
use shield::User as _;
5+
#[cfg(feature = "server")]
6+
use shield_dioxus_axum::ExtractUser;
7+
#[cfg(feature = "server")]
8+
use shield_memory::User as ShieldUser;
9+
10+
#[derive(Deserialize, PartialEq, Serialize)]
11+
pub struct User {
12+
pub id: String,
13+
pub name: Option<String>,
14+
pub email_addresses: Vec<String>,
15+
}
16+
17+
#[get("/api/user", user: ExtractUser<ShieldUser>)]
18+
pub async fn user() -> Result<Option<User>, ServerFnError> {
19+
let ExtractUser(user) = user;
20+
21+
Ok(if let Some(user) = user {
22+
Some(User {
23+
id: user.id(),
24+
name: user.name(),
25+
email_addresses: user
26+
.email_addresses()
27+
.await
28+
.context("failed to get user email addresses")?
29+
.into_iter()
30+
.map(|email_address| email_address.email)
31+
.collect(),
32+
})
33+
} else {
34+
None
35+
})
36+
}

examples/dioxus-axum/src/home.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,47 @@
11
use dioxus::prelude::*;
22

3+
use crate::api::user;
4+
35
#[component]
46
pub fn Home() -> Element {
7+
let user = use_loader(user)?;
8+
let user = user.read();
9+
510
rsx! {
611
h1 { "Shield Dioxus Axum Example" }
12+
13+
if let Some(user) = user.as_ref() {
14+
p {
15+
b {
16+
"Name: "
17+
}
18+
span {
19+
{user.name.as_deref().unwrap_or("-")}
20+
}
21+
}
22+
23+
p {
24+
b {
25+
"Email addresses:"
26+
}
27+
ul {
28+
for email_address in &user.email_addresses {
29+
li {
30+
"{email_address}"
31+
}
32+
}
33+
}
34+
}
35+
36+
a {
37+
href: "/auth/sign-out",
38+
"Sign out"
39+
}
40+
} else {
41+
a {
42+
href: "/auth/sign-in",
43+
"Sign in"
44+
}
45+
}
746
}
847
}

examples/dioxus-axum/src/main.rs

Lines changed: 67 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod api;
12
mod app;
23
mod home;
34

@@ -13,84 +14,76 @@ fn main() {
1314
}
1415

1516
#[cfg(feature = "server")]
16-
#[tokio::main]
17-
async fn main() {
18-
use std::sync::Arc;
17+
fn main() {
18+
dioxus::serve(|| async move {
19+
use std::sync::Arc;
1920

20-
use axum::{Extension, Router};
21-
use dioxus::{
22-
cli_config::fullstack_address_or_localhost,
23-
prelude::{DioxusRouterExt, *},
24-
};
25-
use shield::{Shield, ShieldOptions};
26-
use shield_bootstrap::BootstrapDioxusStyle;
27-
use shield_dioxus_axum::{AuthRoutes, AxumDioxusIntegration, ShieldLayer};
28-
use shield_email::{EmailMethod, EmailOptions, TracingSender};
29-
use shield_memory::{MemoryStorage, User};
30-
use shield_oidc::{Keycloak, OidcMethod};
31-
use tokio::net::TcpListener;
32-
use tower_sessions::{Expiry, MemoryStore, SessionManagerLayer, cookie::time::Duration};
33-
use tracing::{Level, info};
21+
use axum::{Extension, Router};
22+
use dioxus::{
23+
cli_config::fullstack_address_or_localhost,
24+
prelude::{DioxusRouterExt, *},
25+
};
26+
use shield::{Shield, ShieldOptions};
27+
use shield_bootstrap::BootstrapDioxusStyle;
28+
use shield_dioxus_axum::{AuthRoutes, AxumDioxusIntegration, ShieldLayer};
29+
use shield_email::{EmailMethod, EmailOptions, TracingSender};
30+
use shield_memory::{MemoryStorage, User};
31+
use shield_oidc::{Keycloak, OidcMethod};
32+
use tower_sessions::{Expiry, MemoryStore, SessionManagerLayer, cookie::time::Duration};
3433

35-
// Initialize Dioxus
36-
dioxus::logger::init(Level::DEBUG).unwrap();
37-
let addr = fullstack_address_or_localhost();
34+
let addr = fullstack_address_or_localhost();
3835

39-
// Initialize sessions
40-
let session_store = MemoryStore::default();
41-
let session_layer = SessionManagerLayer::new(session_store)
42-
.with_secure(false)
43-
.with_expiry(Expiry::OnInactivity(Duration::minutes(10)));
36+
// Initialize sessions
37+
let session_store = MemoryStore::default();
38+
let session_layer = SessionManagerLayer::new(session_store)
39+
.with_secure(false)
40+
.with_expiry(Expiry::OnInactivity(Duration::minutes(10)));
4441

45-
// Initialize Shield
46-
let storage = MemoryStorage::new();
47-
let shield = Shield::new(
48-
storage.clone(),
49-
vec![
50-
Arc::new(EmailMethod::new(
51-
EmailOptions::builder()
52-
.secret("secret")
53-
.sender(TracingSender)
54-
.build(),
55-
storage.clone(),
56-
)),
57-
Arc::new(
58-
OidcMethod::new(storage).with_providers([Keycloak::builder(
59-
"keycloak",
60-
"http://localhost:18080/realms/Shield",
61-
"client1",
62-
)
63-
.client_secret("xcpQsaGbRILTljPtX4npjmYMBjKrariJ")
64-
.redirect_url(format!(
65-
"http://localhost:{}/api/auth/oidc/sign-in-callback/keycloak",
66-
dioxus::cli_config::devserver_raw_addr()
67-
.map(|addr| addr.port())
68-
.unwrap_or_else(|| addr.port())
69-
))
70-
.build()]),
71-
),
72-
],
73-
ShieldOptions::default(),
74-
);
75-
let shield_layer = ShieldLayer::new(shield.clone());
42+
// Initialize Shield
43+
let storage = MemoryStorage::new();
44+
let shield = Shield::new(
45+
storage.clone(),
46+
vec![
47+
Arc::new(EmailMethod::new(
48+
EmailOptions::builder()
49+
.secret("secret")
50+
.sender(TracingSender)
51+
.build(),
52+
storage.clone(),
53+
)),
54+
Arc::new(
55+
OidcMethod::new(storage).with_providers([Keycloak::builder(
56+
"keycloak",
57+
"http://localhost:18080/realms/Shield",
58+
"client1",
59+
)
60+
.client_secret("xcpQsaGbRILTljPtX4npjmYMBjKrariJ")
61+
.redirect_url(format!(
62+
"http://localhost:{}/api/auth/oidc/sign-in-callback/keycloak",
63+
dioxus::cli_config::devserver_raw_addr()
64+
.map(|addr| addr.port())
65+
.unwrap_or_else(|| addr.port())
66+
))
67+
.build()]),
68+
),
69+
],
70+
ShieldOptions::default(),
71+
);
72+
let shield_layer = ShieldLayer::new(shield.clone());
7673

77-
// Initialize router
78-
let router = Router::new()
79-
.nest("/api/auth", AuthRoutes::new(shield).router())
80-
.serve_dioxus_application(
81-
ServeConfig::new().context(BootstrapDioxusStyle::default().context()),
82-
App,
83-
)
84-
.layer(Extension(
85-
AxumDioxusIntegration::<User>::default().context(),
86-
))
87-
.layer(shield_layer)
88-
.layer(session_layer);
74+
// Initialize router
75+
let router = Router::new()
76+
.nest("/api/auth", AuthRoutes::new(shield).router())
77+
.serve_dioxus_application(
78+
ServeConfig::new().context(BootstrapDioxusStyle::default().context()),
79+
App,
80+
)
81+
.layer(Extension(
82+
AxumDioxusIntegration::<User>::default().context(),
83+
))
84+
.layer(shield_layer)
85+
.layer(session_layer);
8986

90-
// Start app
91-
info!("listening on http://{}", &addr);
92-
let listener = TcpListener::bind(&addr).await.unwrap();
93-
axum::serve(listener, router.into_make_service())
94-
.await
95-
.unwrap();
87+
Ok(router)
88+
});
9689
}

packages/styles/shield-bootstrap/src/dioxus/input.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub fn FormInput(props: FormInputProps) -> Element {
3131
InputType::Button(_) | InputType::Reset(_) | InputType::Submit(_) => {
3232
return rsx! {
3333
button {
34-
class: "btn btn-outline-primary d-flex align-items-center justify-content-center gap-1",
34+
class: "btn btn-primary w-100 mb-3 d-flex align-items-center justify-content-center gap-2",
3535
name: props.input.name,
3636
type: match props.input.r#type {
3737
InputType::Reset(_) => "reset",

0 commit comments

Comments
 (0)