Set up the most basic of authentication clients

This commit is contained in:
Savanni D'Gerinel 2025-02-20 07:39:35 -05:00
parent e8a8a12de3
commit fd3ca9f561
4 changed files with 57 additions and 36 deletions

View File

@ -92,17 +92,16 @@ struct UserOverview {
}
#[derive(Deserialize, Serialize)]
#[serde(tag = "type", content = "content", rename_all = "kebab-case")]
#[typeshare]
enum AuthResponse<A> {
Success(A),
enum AuthResponse {
Success(SessionId),
PasswordReset(SessionId),
}
#[axum::debug_handler]
async fn check_password(
request: Json<AuthRequest>,
) -> (StatusCode, Json<Option<AuthResponse<SessionId>>>) {
) -> (StatusCode, Json<Option<AuthResponse>>) {
let Json(request) = request;
if request.username == "vakarian" && request.password == "aoeu" {
(
@ -183,21 +182,20 @@ async fn main() {
let app = Router::new()
.route(
"/api/test/health",
get(|| async { (StatusCode::OK, Json(None::<String>)) }),
)
.layer(
CorsLayer::new()
.allow_methods([Method::GET])
.allow_origin(Any),
get(|| async { (StatusCode::OK, Json(None::<String>)) }).layer(
CorsLayer::new()
.allow_methods([Method::GET])
.allow_origin(Any),
),
)
.route(
"/api/test/auth",
post(|req: Json<AuthRequest>| check_password(req)),
)
.layer(
CorsLayer::new()
.allow_methods([Method::POST])
.allow_origin(Any),
post(|req: Json<AuthRequest>| check_password(req)).layer(
CorsLayer::new()
.allow_methods([Method::POST])
.allow_headers([CONTENT_TYPE])
.allow_origin(Any),
),
)
.route(
"/api/test/list-users",
@ -226,13 +224,13 @@ async fn main() {
]),
)
})
}),
)
.layer(
CorsLayer::new()
.allow_headers([AUTHORIZATION])
.allow_methods([Method::GET])
.allow_origin(Any),
})
.layer(
CorsLayer::new()
.allow_headers([AUTHORIZATION])
.allow_methods([Method::GET])
.allow_origin(Any),
),
);
let listener = tokio::net::TcpListener::bind("127.0.0.1:8001")
.await

3
visions/ui/Trunk.toml Normal file
View File

@ -0,0 +1,3 @@
[[proxy]]
backend = "http://localhost:8001/api"
insecure = true

View File

@ -1,3 +1,6 @@
use std::future::Future;
use gloo_console::log;
use gloo_net::http::{Request, Response};
use serde::{Deserialize, Serialize};
use wasm_bindgen_futures::wasm_bindgen::{self, JsValue};
@ -9,15 +12,15 @@ struct AuthRequest {
}
#[derive(Deserialize)]
enum AuthResponse {
Ok(SessionId),
pub enum AuthResponse {
Success(SessionId),
PasswordReset(SessionId),
}
#[derive(Deserialize)]
struct SessionId(String);
pub struct SessionId(pub String);
enum ClientError {
pub enum ClientError {
Unauthorized,
Err(u16),
}
@ -31,9 +34,9 @@ struct UserInfo {
name: String,
}
trait Client {
async fn auth(username: String, password: String) -> Result<AuthResponse, ClientError>;
async fn list_users(session_id: SessionId) -> Result<Vec<UserInfo>, ClientError>;
pub trait Client {
fn auth(&self, username: String, password: String) -> impl Future<Output = Result<AuthResponse, ClientError>>;
fn list_users(&self, session_id: SessionId) -> impl Future<Output = Result<Vec<UserInfo>, ClientError>>;
}
pub struct Connection;
@ -43,9 +46,11 @@ impl Connection {
}
impl Client for Connection {
async fn auth(username: String, password: String) -> Result<AuthResponse, ClientError> {
let response: Response = Request::post("http://localhost:8001")
.body(serde_wasm_bindgen::to_value(&AuthRequest{ username, password }).unwrap())
async fn auth(&self, username: String, password: String) -> Result<AuthResponse, ClientError> {
log!("authenticating: ", &username, &password);
let response: Response = Request::post("/api/test/auth")
.header("Content-Type", "application/json")
.body(serde_wasm_bindgen::to_value(&serde_json::to_string(&AuthRequest{ username, password }).unwrap()).unwrap())
.unwrap()
.send()
.await
@ -58,7 +63,7 @@ impl Client for Connection {
}
}
async fn list_users(session_id: SessionId) -> Result<Vec<UserInfo>, ClientError> {
async fn list_users(&self, session_id: SessionId) -> Result<Vec<UserInfo>, ClientError> {
todo!()
}
}

View File

@ -27,6 +27,7 @@ impl Reducible for AuthInfo {
type Action = AuthAction;
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
// log!("reduce", action);
match action {
AuthAction::Auth(session_id) => Self {
session_id: Some(session_id),
@ -98,11 +99,25 @@ fn Login(LoginProps { on_login }: &LoginProps) -> Html {
#[function_component]
fn App() -> Html {
let auth_info = use_reducer(AuthInfo::default);
let client = Connection::new();
let on_login = {
let auth_info = auth_info.clone();
Callback::from(move |(username, password)| auth_info.dispatch(AuthAction::Auth(username)))
Callback::from(move |(username, password)| {
let auth_info = auth_info.clone();
wasm_bindgen_futures::spawn_local(async move {
let client = Connection::new();
match client.auth(username, password).await {
Ok(AuthResponse::Success(session_id)) => {
auth_info.dispatch(AuthAction::Auth(session_id.0))
}
Ok(AuthResponse::PasswordReset(session_id)) => {
auth_info.dispatch(AuthAction::Auth(session_id.0))
}
Err(ClientError::Unauthorized) => todo!(),
Err(ClientError::Err(status)) => todo!(),
};
})
})
};
if auth_info.session_id.is_some() {