implement auth login with a JWT cookie

This commit is contained in:
Douze Bé 2024-10-22 23:21:11 +02:00
parent b5a71c87ad
commit 84bffc5f72
6 changed files with 86 additions and 6 deletions

View file

@ -8,7 +8,10 @@ Login
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
<img class="mx-auto h-12 w-auto" src="https://nixin.distrilab.eu/logo-nixin.svg" alt="NixiN">
<h2 class="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">Index</h2>
<h2 class="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
Index
</h2>
hello user {{user.name}}
</div>
</div>

View file

@ -34,7 +34,7 @@ Login
</div>
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
<form class="space-y-6" action="#" method="POST">
<form class="space-y-6" action="/login" method="POST">
<div>
<label for="email" class="block text-sm font-medium leading-6 text-gray-900">Email address</label>
<div class="mt-2">

View file

@ -0,0 +1,17 @@
{% extends "base.html" %}
{% block title %}
Login
{% endblock title %}
{% block content %}
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
<img class="mx-auto h-12 w-auto" src="https://nixin.distrilab.eu/logo-nixin.svg" alt="NixiN">
<h2 class="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
Register a new account
</h2>
</div>
</div>
{% endblock content %}

View file

@ -146,3 +146,6 @@ auth:
secret: jECGaGSsMtQmKyYyGuk7
# Token expiration time in seconds
expiration: 604800 # 7 days
location:
from: Cookie
name: token

View file

@ -2,8 +2,18 @@
#![allow(clippy::unnecessary_struct_initialization)]
#![allow(clippy::unused_async)]
use loco_rs::prelude::*;
use axum::debug_handler;
use axum::{extract::State, Json};
use axum::{
debug_handler,
extract::State,
extract::Query,
response::{IntoResponse, Redirect},
http::StatusCode,
Json,
Form};
use axum_extra::extract::cookie::{CookieJar, Cookie};
use serde::{Deserialize, Serialize};
use loco_rs::{
app::AppContext,
controller::middleware,
@ -11,7 +21,10 @@ use loco_rs::{
};
use crate::{
models::users,
models::{
users,
//users::{LoginParams, RegisterParams},
},
views,
controllers::middleware::auth_no_error,
};
@ -36,8 +49,52 @@ pub async fn home(
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LoginParams {
pub email: Option<String>,
pub password: Option<String>,
}
/// Creates a user login and returns a token
#[debug_handler]
pub async fn login(
auth: auth_no_error::JWTWithUserOpt<users::Model>,
//ViewEngine(v): ViewEngine<TeraView>,
State(ctx): State<AppContext>,
jar: CookieJar,
Form(params): Form<LoginParams>) -> Result<(CookieJar, Redirect), StatusCode> {
println!("Auth: {:?}",auth);
println!("Form parameters: {:?}",params);
println!("Cookie jar: {:?}",jar);
match params {
LoginParams{email: Some(email), password: Some(password)} => {
let user = users::Model::find_by_email(&ctx.db, &email).await
.or_else(|_| Err(StatusCode::UNAUTHORIZED))?;
let valid = user.verify_password(&password);
if !valid {
return Err(StatusCode::UNAUTHORIZED);
}
let jwt_secret = ctx.config.get_jwt_config()
.or_else(|_| Err(StatusCode::UNAUTHORIZED))?;
let token = user
.generate_jwt(&jwt_secret.secret, &jwt_secret.expiration)
.or_else(|_| Err(StatusCode::UNAUTHORIZED))?;
Ok((
// the updated jar must be returned for the changes
// to be included in the response
jar.add(Cookie::new("token", token)),
Redirect::to("/"),))
}
_ => {
Err(StatusCode::UNAUTHORIZED)
}
}
}
pub fn routes() -> Routes {
Routes::new()
//.prefix("homes")
.add("/", get(home))
.add("/login", post(login))
}

View file

@ -17,6 +17,6 @@ pub fn login(v: &impl ViewRenderer) -> Result<Response> {
///
/// When there is an issue with rendering the view.
pub fn index(v: &impl ViewRenderer, user: &users::Model) -> Result<Response> {
format::render().view(v, "server/show.html", data!({"user": user}))
format::render().view(v, "home/index.html", data!({"user": user}))
}