Pass username/password to the server and allow login failure

This commit is contained in:
pjht 2024-10-17 11:50:48 -05:00
parent c94105acc3
commit c21054814c
Signed by: pjht
GPG Key ID: CA239FC6934E6F3A
3 changed files with 72 additions and 10 deletions

View File

@ -11,3 +11,12 @@ pub struct ChatMessage {
pub struct LoggedInResponse {
pub logged_in: bool,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct LoginRequest {
pub username: String,
pub password: String,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct LoginResponse(pub Result<(), String>);

View File

@ -1,10 +1,12 @@
use crate::components::Nav;
use common::LoggedInResponse;
use common::{LoggedInResponse, LoginRequest, LoginResponse};
use gloo::{
console::{error, log},
history::{BrowserHistory, History},
net::http::Request,
};
use serde::{Deserialize, Serialize};
use web_sys::HtmlInputElement;
use yew::{platform::spawn_local, prelude::*};
use yew_hooks::use_mount;
@ -24,7 +26,10 @@ impl Default for LoginQuery {
#[function_component]
#[allow(non_snake_case)] // Component names should be in PascalCase
pub fn Login() -> Html {
let username_ref = use_node_ref();
let password_ref = use_node_ref();
let disable_input = use_state(|| false);
let login_error = use_state(|| None);
let query_params = BrowserHistory::new()
.location()
.query::<LoginQuery>()
@ -33,9 +38,16 @@ pub fn Login() -> Html {
let login_submitted = {
let disable_input = disable_input.clone();
let redirect = redirect.clone();
let username_ref = username_ref.clone();
let password_ref = password_ref.clone();
let login_error = login_error.clone();
move || {
disable_input.set(true);
let disable_input = disable_input.clone();
let redirect = redirect.clone();
let username_ref = username_ref.clone();
let password_ref = password_ref.clone();
let login_error = login_error.clone();
spawn_local(async move {
let location = web_sys::window().unwrap().location();
let login_url = format!(
@ -43,13 +55,40 @@ pub fn Login() -> Html {
location.protocol().unwrap(),
location.host().unwrap()
);
Request::post(&login_url)
.body("")
let username = username_ref.cast::<HtmlInputElement>().unwrap().value();
let password = password_ref.cast::<HtmlInputElement>().unwrap().value();
let req_body = LoginRequest { username, password };
let resp = match Request::post(&login_url)
.json(&req_body)
.unwrap()
.send()
.await
.unwrap();
BrowserHistory::new().push(&redirect);
{
Ok(val) => val,
Err(err) => {
error!(format!("Could not send login request to server: {err}"));
login_error.set(Some("Error logging in".to_string()));
disable_input.set(false);
return;
}
};
let LoginResponse(resp) = match resp.json().await {
Ok(val) => val,
Err(err) => {
error!(format!("Could not parse login response: {err}"));
login_error.set(Some("Error logging in".to_string()));
disable_input.set(false);
return;
}
};
match resp {
Ok(_) => BrowserHistory::new().push(&redirect),
Err(err) => {
login_error.set(Some(err));
password_ref.cast::<HtmlInputElement>().unwrap().set_value("");
disable_input.set(false);
}
};
});
}
};
@ -92,20 +131,25 @@ pub fn Login() -> Html {
style="max-width: 570px"
>
<h1>{ "Login" }</h1>
if login_error.is_some() {
<div class="alert alert-danger" role="alert">
{ login_error.as_ref().unwrap() }
</div>
}
<input
type="text"
id="username"
class="form-control"
placeholder="Username"
disabled={*disable_input}
ref={username_ref}
/>
<input
type="password"
id="password"
class="form-control"
placeholder="Password"
disabled={*disable_input}
onkeydown={password_keypress}
ref={password_ref}
/>
if !*disable_input {
<input

View File

@ -9,7 +9,7 @@ use axum::{async_trait, Json};
use axum::{routing::get, Router};
use axum_login::{AuthManagerLayerBuilder, AuthSession, AuthUser, AuthnBackend, UserId};
use clap::Parser;
use common::{ChatMessage, LoggedInResponse};
use common::{ChatMessage, LoggedInResponse, LoginRequest, LoginResponse};
use futures::stream::SplitSink;
use futures::{SinkExt, StreamExt};
use slab::Slab;
@ -124,11 +124,20 @@ async fn serve_index(static_dir: &Path) -> Response {
.unwrap()
}
async fn login(mut auth_session: AuthSession<DummyAuthBackend>) -> Response {
async fn login(
mut auth_session: AuthSession<DummyAuthBackend>,
Json(req): Json<LoginRequest>,
) -> Response {
if req.username != "pjht" || req.password != "123456" {
return Json(LoginResponse(Err(
"Invalid username or password".to_string()
)))
.into_response();
}
if auth_session.login(&DummyAuthUser).await.is_err() {
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
}
StatusCode::OK.into_response()
Json(LoginResponse(Ok(()))).into_response()
}
async fn logout(mut auth_session: AuthSession<DummyAuthBackend>) -> Response {