From fb5aa5ee5a6973667184ee352c85e606c9e9c5cd Mon Sep 17 00:00:00 2001 From: Marko Korhonen Date: Fri, 8 May 2020 09:35:28 +0300 Subject: [PATCH] Add example protected route to project --- .../backend/src/handlers/authentication.rs | 27 +---- project/backend/src/handlers/logged_user.rs | 25 +++++ project/backend/src/handlers/mod.rs | 2 + project/backend/src/handlers/protected.rs | 14 +++ project/backend/src/main.rs | 3 +- project/frontend/src/component/login.rs | 13 +-- project/frontend/src/component/mod.rs | 1 + project/frontend/src/component/protected.rs | 104 ++++++++++++++++++ project/frontend/src/main.rs | 8 +- 9 files changed, 161 insertions(+), 36 deletions(-) create mode 100644 project/backend/src/handlers/logged_user.rs create mode 100644 project/backend/src/handlers/protected.rs create mode 100644 project/frontend/src/component/protected.rs diff --git a/project/backend/src/handlers/authentication.rs b/project/backend/src/handlers/authentication.rs index 58ef898..1abbe6e 100644 --- a/project/backend/src/handlers/authentication.rs +++ b/project/backend/src/handlers/authentication.rs @@ -1,34 +1,13 @@ use crate::{ db_connection::DbPool, errors::CustomError, + handlers::logged_user::LoggedUser, handlers::pool_handler, models::user::{AuthUser, DeleteUser, RegisterUser, User}, - utils::jwt::{decode_token, encode_token, UserWithToken}, + utils::jwt::encode_token, }; use actix_identity::Identity; -use actix_web::{dev::Payload, web, FromRequest, HttpRequest, HttpResponse}; -use futures::future::Future; -use std::pin::Pin; - -pub type LoggedUser = UserWithToken; - -impl FromRequest for LoggedUser { - type Error = HttpResponse; - type Config = (); - type Future = Pin>>>; - - fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { - let fut = Identity::from_request(req, payload); - - Box::pin(async move { - if let Some(identity) = fut.await?.identity() { - let user = decode_token(&identity)?; - return Ok(user); - }; - Err(HttpResponse::Unauthorized().finish()) - }) - } -} +use actix_web::{web, HttpResponse}; pub async fn register( new_user: web::Json, diff --git a/project/backend/src/handlers/logged_user.rs b/project/backend/src/handlers/logged_user.rs new file mode 100644 index 0000000..de21cba --- /dev/null +++ b/project/backend/src/handlers/logged_user.rs @@ -0,0 +1,25 @@ +use crate::utils::jwt::{decode_token, UserWithToken}; +use actix_identity::Identity; +use actix_web::{dev::Payload, FromRequest, HttpRequest, HttpResponse}; +use futures::future::Future; +use std::pin::Pin; + +pub type LoggedUser = UserWithToken; + +impl FromRequest for LoggedUser { + type Error = HttpResponse; + type Config = (); + type Future = Pin>>>; + + fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { + let fut = Identity::from_request(req, payload); + + Box::pin(async move { + if let Some(identity) = fut.await?.identity() { + let user = decode_token(&identity)?; + return Ok(user); + }; + Err(HttpResponse::Unauthorized().finish()) + }) + } +} diff --git a/project/backend/src/handlers/mod.rs b/project/backend/src/handlers/mod.rs index 2d5adc7..5875886 100644 --- a/project/backend/src/handlers/mod.rs +++ b/project/backend/src/handlers/mod.rs @@ -2,6 +2,8 @@ use crate::db_connection::{DbPool, MyPooledConnection}; use actix_web::{web, HttpResponse}; pub mod authentication; +pub mod logged_user; +pub mod protected; pub fn pool_handler(pool: web::Data) -> Result { pool.get() diff --git a/project/backend/src/handlers/protected.rs b/project/backend/src/handlers/protected.rs new file mode 100644 index 0000000..abb3a2e --- /dev/null +++ b/project/backend/src/handlers/protected.rs @@ -0,0 +1,14 @@ +use crate::handlers::logged_user::LoggedUser; +use actix_web::HttpResponse; +use serde::Serialize; + +#[derive(Serialize)] +struct SuccessMessage { + message: String, +} + +pub async fn protected_route(_user: LoggedUser) -> Result { + Ok(HttpResponse::Ok().json(SuccessMessage { + message: String::from("Tämä on suojattu viesti palvelimelta"), + })) +} diff --git a/project/backend/src/main.rs b/project/backend/src/main.rs index 655fee7..157a13d 100644 --- a/project/backend/src/main.rs +++ b/project/backend/src/main.rs @@ -22,7 +22,7 @@ use actix_web::{ use chrono::Duration; use db_connection::get_pool; use dotenv::dotenv; -use handlers::authentication; +use handlers::{authentication, protected}; pub fn get_env(var_name: &str) -> String { match std::env::var(&var_name) { @@ -96,6 +96,7 @@ async fn main() -> std::io::Result<()> { .service(resource("/logout").route(post().to(authentication::logout))) .service(resource("/delete").route(delete().to(authentication::delete))), ) + .service(resource("/api/protected").route(get().to(protected::protected_route))) .service(api_404_unconfigured) .service(Files::new("/", "./static").index_file("index.html")) .default_service(get().to(serve_index_html)) diff --git a/project/frontend/src/component/login.rs b/project/frontend/src/component/login.rs index 491bb69..4465844 100644 --- a/project/frontend/src/component/login.rs +++ b/project/frontend/src/component/login.rs @@ -1,4 +1,3 @@ -use crate::utils::cookie; use log::{error, info}; use serde_json::json; use yew::format::Json; @@ -50,7 +49,6 @@ impl LoginComponent { if meta.status.is_success() { Msg::FetchReady(body.unwrap()) } else { - error!("{}", body.unwrap()); Msg::FetchError } }); @@ -97,9 +95,6 @@ impl Component for LoginComponent { Msg::FetchReady(response) => { self.fetching = false; info!("Login successful: {}", response); - cookie::get("thesis") - .map(|cookie| info!("Cookie: {}", cookie)) - .map_err(|e| error!("{}", e)); } Msg::FetchError => { @@ -121,16 +116,16 @@ impl Component for LoginComponent { html! {
-

{ "Please log in" }

+

{ "Kirjaudu sisään" }

- { "Log in" } + { "Kirjaudu" }
diff --git a/project/frontend/src/component/mod.rs b/project/frontend/src/component/mod.rs index 320cbbb..2e59232 100644 --- a/project/frontend/src/component/mod.rs +++ b/project/frontend/src/component/mod.rs @@ -1 +1,2 @@ pub mod login; +pub mod protected; diff --git a/project/frontend/src/component/protected.rs b/project/frontend/src/component/protected.rs new file mode 100644 index 0000000..dce2111 --- /dev/null +++ b/project/frontend/src/component/protected.rs @@ -0,0 +1,104 @@ +use log::{error, info}; +use yew::format::Nothing; +use yew::prelude::*; +use yew::services::fetch::{FetchService, FetchTask, Request, Response}; + +pub struct ProtectedComponent { + component_link: ComponentLink, + fetch_service: FetchService, + fetch_task: Option, + fetching: bool, + data: String, +} + +pub enum Msg { + FetchData(), + FetchReady(String), + FetchError, +} + +impl ProtectedComponent { + fn get_data(&mut self) { + self.fetching = true; + + let request = Request::get("http://localhost:3880/api/protected") + .body(Nothing) + .unwrap(); + + info!("Request: {:?}", request); + + let callback = + self.component_link + .callback(|response: Response>| { + let (meta, body) = response.into_parts(); + info!("{}", meta.status); + if meta.status.is_success() { + Msg::FetchReady(body.unwrap()) + } else { + Msg::FetchError + } + }); + + let task = self.fetch_service.fetch(request, callback); + self.fetch_task = Some(task.unwrap()); + } +} + +impl Component for ProtectedComponent { + type Message = Msg; + type Properties = (); + + fn create(_: Self::Properties, link: ComponentLink) -> Self { + Self { + component_link: link, + fetch_service: FetchService::new(), + fetch_task: None, + fetching: false, + data: String::from(""), + } + } + + fn change(&mut self, _: Self::Properties) -> ShouldRender { + true + } + + fn update(&mut self, msg: Self::Message) -> ShouldRender { + match msg { + Msg::FetchReady(response) => { + self.fetching = false; + info!("Fetch successful: {}", response); + self.data = response; + } + + Msg::FetchError => { + self.fetching = false; + error!("There was an error connecting to API"); + self.data = String::from("401 Unauthorized"); + } + + Msg::FetchData() => { + self.fetching = true; + self.get_data(); + } + } + true + } + + fn view(&self) -> Html { + let onclick = self.component_link.callback(|_| Msg::FetchData()); + + html! { +
+

{ "Suojattu data" }

+

{&self.data}

+ +
+ } + } +} diff --git a/project/frontend/src/main.rs b/project/frontend/src/main.rs index e489b04..e26e4bc 100644 --- a/project/frontend/src/main.rs +++ b/project/frontend/src/main.rs @@ -6,7 +6,7 @@ extern crate web_logger; mod component; pub mod utils; -use component::login::LoginComponent; +use component::{login::LoginComponent, protected::ProtectedComponent}; use yew::prelude::*; use yew::virtual_dom::VNode; use yew_router::{prelude::*, switch::Permissive, Switch}; @@ -37,6 +37,10 @@ impl Component for App { fn view(&self) -> VNode { html! {
+ render = Router::render(|switch: AppRoute| { match switch { @@ -44,7 +48,7 @@ impl Component for App { AppRoute::PageNotFound(Permissive(None)) => html!{"Page not found"}, AppRoute::PageNotFound(Permissive(Some(missed_route))) => html!{format!("Page '{}' not found", missed_route)}, AppRoute::Root => { - html!{"hello there!"} + html!{} }, } })