use std::collections::HashMap; use rocket::outcome::IntoOutcome; use rocket::request::{self, FlashMessage, FromRequest, Request}; use rocket::response::{Redirect, Flash}; use rocket::http::{Cookie, CookieJar}; use rocket::form::Form; use rocket_contrib::templates::Template; #[derive(FromForm)] struct Login<'r> { username: &'r str, password: &'r str } #[derive(Debug)] struct User(usize); #[rocket::async_trait] impl<'r> FromRequest<'r> for User { type Error = std::convert::Infallible; async fn from_request(request: &'r Request<'_>) -> request::Outcome { request.cookies() .get_private("user_id") .and_then(|cookie| cookie.value().parse().ok()) .map(User) .or_forward(()) } } #[macro_export] macro_rules! session_uri { ($($t:tt)*) => (rocket::uri!("/session", $crate::session:: $($t)*)) } pub use session_uri as uri; #[get("/")] fn index(user: User) -> Template { let mut context = HashMap::new(); context.insert("user_id", user.0); Template::render("session", &context) } #[get("/", rank = 2)] fn no_auth_index() -> Redirect { Redirect::to(uri!(login_page)) } #[get("/login")] fn login(_user: User) -> Redirect { Redirect::to(uri!(index)) } #[get("/login", rank = 2)] fn login_page(flash: Option>) -> Template { Template::render("login", &flash) } #[post("/login", data = "")] fn post_login(jar: &CookieJar<'_>, login: Form>) -> Result> { if login.username == "Sergio" && login.password == "password" { jar.add_private(Cookie::new("user_id", 1.to_string())); Ok(Redirect::to(uri!(index))) } else { Err(Flash::error(Redirect::to(uri!(login_page)), "Invalid username/password.")) } } #[post("/logout")] fn logout(jar: &CookieJar<'_>) -> Flash { jar.remove_private(Cookie::named("user_id")); Flash::success(Redirect::to(uri!(login_page)), "Successfully logged out.") } pub fn routes() -> Vec { routes![index, no_auth_index, login, login_page, post_login, logout] }