End-to-end web-based signup, login, and logout flows work.
This commit is contained in:
parent
113982ba27
commit
d2613b0ef9
8 changed files with 95 additions and 15 deletions
|
@ -1,15 +1,19 @@
|
||||||
use axum::response::{IntoResponse, Redirect};
|
use axum::response::{IntoResponse, Redirect};
|
||||||
|
|
||||||
use crate::AuthContext;
|
use crate::{templates::Index, AuthContext};
|
||||||
|
|
||||||
pub async fn handle_slash_redir() -> impl IntoResponse {
|
pub async fn handle_slash_redir() -> impl IntoResponse {
|
||||||
Redirect::temporary("/")
|
Redirect::temporary("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_slash(auth: AuthContext) -> impl IntoResponse {
|
pub async fn handle_slash(auth: AuthContext) -> impl IntoResponse {
|
||||||
if let Some(user) = auth.current_user {
|
if let Some(ref user) = auth.current_user {
|
||||||
tracing::debug!("Logged in as: {user}");
|
let name = &user.username;
|
||||||
|
tracing::debug!("Logged in as: {name}");
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("Not logged in.")
|
tracing::debug!("Not logged in.");
|
||||||
|
}
|
||||||
|
Index {
|
||||||
|
user: auth.current_user,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/login.rs
15
src/login.rs
|
@ -11,7 +11,7 @@ use axum::{
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
templates::{LoginGet, LoginPost},
|
templates::{LoginGet, LoginPost, LogoutGet, LogoutPost},
|
||||||
util::form_decode,
|
util::form_decode,
|
||||||
AuthContext, User,
|
AuthContext, User,
|
||||||
};
|
};
|
||||||
|
@ -41,12 +41,12 @@ pub enum LoginErrorKind {
|
||||||
impl IntoResponse for LoginError {
|
impl IntoResponse for LoginError {
|
||||||
fn into_response(self) -> Response {
|
fn into_response(self) -> Response {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
LoginErrorKind::Unknown => (
|
LoginErrorKind::Unknown | LoginErrorKind::Internal => (
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
"An unknown error occurred; you cursed, brah?",
|
"An unknown error occurred; you cursed, brah?",
|
||||||
)
|
)
|
||||||
.into_response(),
|
.into_response(),
|
||||||
_ => (StatusCode::BAD_REQUEST, format!("{self}")).into_response(),
|
_ => (StatusCode::OK, format!("{self}")).into_response(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,9 +99,12 @@ pub async fn get_login() -> impl IntoResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_logout() -> impl IntoResponse {
|
pub async fn get_logout() -> impl IntoResponse {
|
||||||
todo!()
|
LogoutGet
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn post_logout() -> impl IntoResponse {
|
pub async fn post_logout(mut auth: AuthContext) -> impl IntoResponse {
|
||||||
todo!()
|
if auth.current_user.is_some() {
|
||||||
|
auth.logout().await;
|
||||||
|
}
|
||||||
|
LogoutPost
|
||||||
}
|
}
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -1,7 +1,10 @@
|
||||||
use std::net::SocketAddr;
|
use std::{net::SocketAddr, time::Duration};
|
||||||
|
|
||||||
use axum::{routing::get, Router};
|
use axum::{routing::get, Router};
|
||||||
use axum_login::{axum_sessions::SessionLayer, AuthLayer, SqliteStore};
|
use axum_login::{
|
||||||
|
axum_sessions::{PersistencePolicy, SessionLayer},
|
||||||
|
AuthLayer, SqliteStore,
|
||||||
|
};
|
||||||
use rand_core::{OsRng, RngCore};
|
use rand_core::{OsRng, RngCore};
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
use witch_watch::{
|
use witch_watch::{
|
||||||
|
@ -26,7 +29,7 @@ async fn main() {
|
||||||
let pool = db::get_pool().await;
|
let pool = db::get_pool().await;
|
||||||
|
|
||||||
let secret = {
|
let secret = {
|
||||||
let mut bytes = [0u8; 128];
|
let mut bytes = [0u8; 64];
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
rng.fill_bytes(&mut bytes);
|
rng.fill_bytes(&mut bytes);
|
||||||
bytes
|
bytes
|
||||||
|
@ -35,7 +38,10 @@ async fn main() {
|
||||||
let session_layer = {
|
let session_layer = {
|
||||||
let store = SqliteSessionStore::from_client(pool.clone());
|
let store = SqliteSessionStore::from_client(pool.clone());
|
||||||
store.migrate().await.expect("Could not migrate session DB");
|
store.migrate().await.expect("Could not migrate session DB");
|
||||||
SessionLayer::new(store, &secret).with_secure(true)
|
SessionLayer::new(store, &secret)
|
||||||
|
.with_secure(true)
|
||||||
|
.with_persistence_policy(PersistencePolicy::ExistingOnly)
|
||||||
|
.with_session_ttl(Some(Duration::from_secs(3600 * 24 * 366)))
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth_layer = {
|
let auth_layer = {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::User;
|
||||||
|
|
||||||
#[derive(Debug, Default, Template, Deserialize, Serialize)]
|
#[derive(Debug, Default, Template, Deserialize, Serialize)]
|
||||||
#[template(path = "signup.html")]
|
#[template(path = "signup.html")]
|
||||||
pub struct CreateUser {
|
pub struct CreateUser {
|
||||||
|
@ -24,3 +26,17 @@ pub struct LoginGet {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Template, Deserialize, Serialize)]
|
||||||
|
#[template(path = "logout_get.html")]
|
||||||
|
pub struct LogoutGet;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Template, Deserialize, Serialize)]
|
||||||
|
#[template(path = "logout_post.html")]
|
||||||
|
pub struct LogoutPost;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Template, Deserialize, Serialize)]
|
||||||
|
#[template(path = "index.html")]
|
||||||
|
pub struct Index {
|
||||||
|
pub user: Option<User>,
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use axum_login::{secrecy::SecretVec, AuthUser};
|
use axum_login::{secrecy::SecretVec, AuthUser};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
const USERNAME_QUERY: &str = "select * from witches where username = $1";
|
const USERNAME_QUERY: &str = "select * from witches where username = $1";
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq, sqlx::FromRow)]
|
#[derive(Debug, Default, Clone, PartialEq, Eq, sqlx::FromRow, Serialize, Deserialize)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
|
|
26
templates/index.html
Normal file
26
templates/index.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Welcome to Witch Watch, Bish{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Welcome to Witch Watch</h1>
|
||||||
|
|
||||||
|
{% match user %}
|
||||||
|
{% when Some with (usr) %}
|
||||||
|
<p>
|
||||||
|
Hello, {{ usr.username }}! It's nice to see you.
|
||||||
|
</p>
|
||||||
|
</br>
|
||||||
|
<p>
|
||||||
|
<form action="/logout" enctype="application/x-www-form-urlencoded" method="post">
|
||||||
|
<input type="submit" value="sign out?">
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p>
|
||||||
|
Heya, why don't you <a href="/login">log in</a> or <a href="/signup">sign up</a>?
|
||||||
|
</p>
|
||||||
|
{% endmatch %}
|
||||||
|
|
||||||
|
{% endblock %}
|
13
templates/logout_get.html
Normal file
13
templates/logout_get.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Logout of Witch Watch, Bish{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<form action="/logout" enctype="application/x-www-form-urlencoded" method="post">
|
||||||
|
<input type="submit" value="Sign out">
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% endblock %}
|
11
templates/logout_post.html
Normal file
11
templates/logout_post.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Thanks for Signing Up for Witch Watch, Bish{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Goodbye</h1>
|
||||||
|
|
||||||
|
<p>Good bye! May we suggest checking out <a href="/">our home page</a>?</p>
|
||||||
|
|
||||||
|
{% endblock %}
|
Loading…
Reference in a new issue