admin pages
Pages can now be locked behind admin privileges
This commit is contained in:
@@ -163,7 +163,8 @@ pub async fn get_current_user(
|
|||||||
"data": json!({
|
"data": json!({
|
||||||
"id": user.id,
|
"id": user.id,
|
||||||
"first_name": user.first_name,
|
"first_name": user.first_name,
|
||||||
"last_name": user.last_name
|
"last_name": user.last_name,
|
||||||
|
"is_admin": user.is_admin
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,22 +5,27 @@ use yew_router::prelude::*;
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct AuthState {
|
pub struct AuthState {
|
||||||
pub is_authenticated: bool,
|
pub is_authenticated: Option<bool>,
|
||||||
|
pub is_admin: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, PartialEq)]
|
#[derive(Properties, PartialEq)]
|
||||||
pub struct ProtectedRouteProps {
|
pub struct ProtectedRouteProps {
|
||||||
pub children: Children,
|
pub children: Children,
|
||||||
|
pub admin_page: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component(ProtectedRoute)]
|
#[component(ProtectedRoute)]
|
||||||
pub fn protected_route(props: &ProtectedRouteProps) -> Html {
|
pub fn protected_route(props: &ProtectedRouteProps) -> Html {
|
||||||
let is_authenticated = use_state(|| None::<bool>);
|
let auth_state = use_state(|| AuthState {
|
||||||
|
is_authenticated: None,
|
||||||
|
is_admin: None,
|
||||||
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
let is_authenticated = is_authenticated.clone();
|
let auth_state = auth_state.clone();
|
||||||
use_effect_with((), move |_| {
|
use_effect_with((), move |_| {
|
||||||
let is_authenticated = is_authenticated.clone();
|
let auth_state = auth_state.clone();
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
match Request::get("/api/users/current")
|
match Request::get("/api/users/current")
|
||||||
.credentials(web_sys::RequestCredentials::Include)
|
.credentials(web_sys::RequestCredentials::Include)
|
||||||
@@ -31,14 +36,27 @@ pub fn protected_route(props: &ProtectedRouteProps) -> Html {
|
|||||||
let status = resp.status();
|
let status = resp.status();
|
||||||
web_sys::console::log_1(&format!("Auth check: status {}", status).into());
|
web_sys::console::log_1(&format!("Auth check: status {}", status).into());
|
||||||
if status == 200 {
|
if status == 200 {
|
||||||
is_authenticated.set(Some(true));
|
let user_data: serde_json::Value =
|
||||||
|
resp.json().await.unwrap_or_default();
|
||||||
|
let is_admin = user_data["data"]["is_admin"].as_bool();
|
||||||
|
|
||||||
|
auth_state.set(AuthState {
|
||||||
|
is_authenticated: Some(true),
|
||||||
|
is_admin,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
is_authenticated.set(Some(false));
|
auth_state.set(AuthState {
|
||||||
|
is_authenticated: Some(false),
|
||||||
|
is_admin: Some(false),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
web_sys::console::log_1(&format!("Auth check error: {:?}", err).into());
|
web_sys::console::log_1(&format!("Auth check error: {:?}", err).into());
|
||||||
is_authenticated.set(Some(false));
|
auth_state.set(AuthState {
|
||||||
|
is_authenticated: Some(false),
|
||||||
|
is_admin: Some(false),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -46,13 +64,33 @@ pub fn protected_route(props: &ProtectedRouteProps) -> Html {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
match *is_authenticated {
|
match (*auth_state) {
|
||||||
None => html! { <div>{"Loading..."}</div> },
|
AuthState {
|
||||||
Some(true) => props.children.clone().into(),
|
is_authenticated: None,
|
||||||
Some(false) => {
|
..
|
||||||
html! {
|
} => html! { <div>{ "Loading..." } </div> },
|
||||||
<Redirect<crate::Route> to={crate::Route::Login} />
|
AuthState {
|
||||||
|
is_authenticated: Some(false),
|
||||||
|
..
|
||||||
|
} => html! {
|
||||||
|
<Redirect<crate::Route> to={crate::Route::Login}/>
|
||||||
|
},
|
||||||
|
AuthState {
|
||||||
|
is_authenticated: Some(true),
|
||||||
|
is_admin: admin_flag,
|
||||||
|
} => {
|
||||||
|
if props.admin_page {
|
||||||
|
match admin_flag {
|
||||||
|
Some(true) => props.children.clone().into(),
|
||||||
|
Some(false) => {
|
||||||
|
html! { <Redirect<crate::Route> to={crate::Route::PermissionDenied}/> }
|
||||||
|
}
|
||||||
|
None => html! { <div>{ "Checking permissions..." }</div> },
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props.children.clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => html! { <div>{ "Checking permissions..." }</div> },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
mod pages;
|
|
||||||
mod auth;
|
mod auth;
|
||||||
use crate::pages::*;
|
mod pages;
|
||||||
use crate::auth::ProtectedRoute;
|
use crate::auth::ProtectedRoute;
|
||||||
|
use crate::pages::*;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::prelude::*;
|
use yew_router::prelude::*;
|
||||||
|
|
||||||
@@ -23,6 +23,8 @@ enum Route {
|
|||||||
AllUsers,
|
AllUsers,
|
||||||
#[at("/users/:id")]
|
#[at("/users/:id")]
|
||||||
UserByID { id: i16 },
|
UserByID { id: i16 },
|
||||||
|
#[at("/denied")]
|
||||||
|
PermissionDenied,
|
||||||
#[not_found]
|
#[not_found]
|
||||||
#[at("/404")]
|
#[at("/404")]
|
||||||
NotFound,
|
NotFound,
|
||||||
@@ -31,42 +33,43 @@ enum Route {
|
|||||||
fn switch(route: Route) -> Html {
|
fn switch(route: Route) -> Html {
|
||||||
match route {
|
match route {
|
||||||
Route::Home => html! {
|
Route::Home => html! {
|
||||||
<ProtectedRoute>
|
<ProtectedRoute admin_page={false}>
|
||||||
<basic_pages::Home/>
|
<basic_pages::Home/>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
},
|
},
|
||||||
Route::NotFound => html! { <basic_pages::NotFound/> },
|
Route::NotFound => html! { <basic_pages::NotFound/> },
|
||||||
Route::Ticket => html! {
|
Route::Ticket => html! {
|
||||||
<ProtectedRoute>
|
<ProtectedRoute admin_page={false}>
|
||||||
<ticket::SubmitTicket/>
|
<ticket::SubmitTicket/>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
},
|
},
|
||||||
Route::TicketById { id } => html! {
|
Route::TicketById { id } => html! {
|
||||||
<ProtectedRoute>
|
<ProtectedRoute admin_page={true}>
|
||||||
<ticket::TicketByID {id}/>
|
<ticket::TicketByID {id}/>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
},
|
},
|
||||||
Route::AllTickets => html! {
|
Route::AllTickets => html! {
|
||||||
<ProtectedRoute>
|
<ProtectedRoute admin_page={false}>
|
||||||
<ticket::AllTickets/>
|
<ticket::AllTickets/>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
},
|
},
|
||||||
Route::Register => html! {
|
Route::Register => html! {
|
||||||
<ProtectedRoute>
|
<ProtectedRoute admin_page={true}>
|
||||||
<user::Register/>
|
<user::Register/>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
},
|
},
|
||||||
Route::Login => html! { <user::Login/> },
|
Route::Login => html! { <user::Login/> },
|
||||||
Route::AllUsers => html! {
|
Route::AllUsers => html! {
|
||||||
<ProtectedRoute>
|
<ProtectedRoute admin_page={true}>
|
||||||
<user::AllUsers/>
|
<user::AllUsers/>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
},
|
},
|
||||||
Route::UserByID { id } => html! {
|
Route::UserByID { id } => html! {
|
||||||
<ProtectedRoute>
|
<ProtectedRoute admin_page={true}>
|
||||||
<user::UserByID {id}/>
|
<user::UserByID {id}/>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
},
|
},
|
||||||
|
Route::PermissionDenied => html! { <basic_pages::PermissionDenied/> },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,3 +28,13 @@ pub fn not_found_component() -> Html {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[component(PermissionDenied)]
|
||||||
|
pub fn denied_component() -> Html {
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<h1>{ "Sie haben nicht die benötigten Rechte um diese Seite aufzurufen" }</h1>
|
||||||
|
<h3>{ "Wenn sie denken, dass dies ein Fehler ist kontaktieren sie Herrn Winter" }</h3>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use gloo_net::http::Request;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use wasm_bindgen_futures::spawn_local;
|
use wasm_bindgen_futures::spawn_local;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
use yew_router::prelude::use_navigator;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
@@ -177,6 +178,7 @@ pub fn login_component() -> Html {
|
|||||||
let loading = use_state(|| false);
|
let loading = use_state(|| false);
|
||||||
let error = use_state(|| String::new());
|
let error = use_state(|| String::new());
|
||||||
let success = use_state(|| false);
|
let success = use_state(|| false);
|
||||||
|
let navigator = use_navigator().unwrap();
|
||||||
|
|
||||||
let onsubmit = {
|
let onsubmit = {
|
||||||
let username = username.clone();
|
let username = username.clone();
|
||||||
@@ -184,6 +186,7 @@ pub fn login_component() -> Html {
|
|||||||
let loading = loading.clone();
|
let loading = loading.clone();
|
||||||
let error = error.clone();
|
let error = error.clone();
|
||||||
let success = success.clone();
|
let success = success.clone();
|
||||||
|
let navigator = navigator.clone();
|
||||||
|
|
||||||
Callback::from(move |e: SubmitEvent| {
|
Callback::from(move |e: SubmitEvent| {
|
||||||
e.prevent_default();
|
e.prevent_default();
|
||||||
@@ -192,6 +195,7 @@ pub fn login_component() -> Html {
|
|||||||
let loading = loading.clone();
|
let loading = loading.clone();
|
||||||
let error = error.clone();
|
let error = error.clone();
|
||||||
let success = success.clone();
|
let success = success.clone();
|
||||||
|
let navigator = navigator.clone();
|
||||||
|
|
||||||
loading.set(true);
|
loading.set(true);
|
||||||
error.set(String::new());
|
error.set(String::new());
|
||||||
@@ -211,7 +215,10 @@ pub fn login_component() -> Html {
|
|||||||
loading.set(false);
|
loading.set(false);
|
||||||
|
|
||||||
match response {
|
match response {
|
||||||
Ok(r) if r.status() == 200 => success.set(true),
|
Ok(r) if r.status() == 200 => {
|
||||||
|
success.set(true);
|
||||||
|
navigator.push(&crate::Route::Home);
|
||||||
|
}
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
let text = r.text().await.unwrap_or_else(|_| "unknown".into());
|
let text = r.text().await.unwrap_or_else(|_| "unknown".into());
|
||||||
error.set(format!("HTTP {}: {}", r.status(), text));
|
error.set(format!("HTTP {}: {}", r.status(), text));
|
||||||
@@ -242,7 +249,6 @@ pub fn login_component() -> Html {
|
|||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<button type="submit" disabled={*loading}>{ if *loading { "Logging in..." } else { "Login" } }</button>
|
<button type="submit" disabled={*loading}>{ if *loading { "Logging in..." } else { "Login" } }</button>
|
||||||
if *success { <p>{"Logged in — cookie set by server"}</p> }
|
|
||||||
if !error.is_empty() { <p style="color:red">{(*error).clone()}</p> }
|
if !error.is_empty() { <p style="color:red">{(*error).clone()}</p> }
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user