Add authentication with session cookie

This commit is contained in:
Lennart
2024-10-13 19:05:57 +02:00
parent c2dbd9d0b9
commit 7ce0fc53a4
9 changed files with 74 additions and 26 deletions

View File

@@ -16,4 +16,4 @@ thiserror = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
actix-web = { workspace = true } actix-web = { workspace = true }
rustical_store = { workspace = true } rustical_store = { workspace = true }
actix-files = "0.6.6" actix-files = "0.6"

View File

@@ -1,2 +1,2 @@
[general] [general]
dirs = ["frontend/dist/src/templates"] dirs = ["frontend/dist/templates"]

View File

@@ -6,6 +6,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}RustiCal{% endblock %}</title> <title>{% block title %}RustiCal{% endblock %}</title>
<script type="module" src="htmx.org"></script> <script type="module" src="htmx.org"></script>
<style>
* {
box-sizing: border-box;
}
</style>
{% block imports %}{% endblock %} {% block imports %}{% endblock %}
</head> </head>

View File

@@ -0,0 +1,9 @@
{% extends "layouts/default.html" %}
{% block imports %}
{% endblock %}
{% block content %}
<h1>Test</h1>
<a href="/frontend/user/{{ calendar.principal }}">Back</a>
{% endblock %}

View File

@@ -1,20 +1,21 @@
{% extends "layouts/default.html" %} {% extends "layouts/default.html" %}
{% block imports %} {% block imports %}
{% endblock %}
{% block content %}
<style> <style>
li { li {
list-style: none; list-style: none;
display: block; display: block;
margin: 12px; margin: 12px;
height: 80px; min-height: 80px;
background: #EEE; background: #EEE;
padding: 8px; padding: 8px;
border-radius: 12px;
} }
</style> </style>
{% endblock %} <h2>Welcome {{ user_id }}!</h2>
{% block content %}
<h2>Welcome {{ owner }}!</h2>
<ul> <ul>
{% for calendar in calendars %} {% for calendar in calendars %}
<li> <li>
@@ -23,9 +24,12 @@ li {
{% else %} {% else %}
{{ calendar.id }} {{ calendar.id }}
{% endif %} {% endif %}
<p> {% let color = calendar.color.to_owned().unwrap_or("red".to_owned()) %}
<p style="color: {{ color }}">
{% if let Some(description) = calendar.description %}{{ description }}{% endif %} {% if let Some(description) = calendar.description %}{{ description }}{% endif %}
</p> </p>
<!-- <a href="{{ calendar.id}}">Test</a> -->
<a href="/frontend/user/{{ user_id }}/{{ calendar.id}}">Test</a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View File

@@ -3,19 +3,9 @@ import { globSync } from 'glob'
import path from 'node:path' import path from 'node:path'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
console.log(
Object.fromEntries(globSync('src/templates/**/*.html').map(file => [
path.relative(
'src',
file.slice(0, file.length - path.extname(file).length)
),
// This expands the relative paths to absolute paths, so e.g.
// src/nested/foo becomes /project/src/nested/foo.js
fileURLToPath(new URL(file, import.meta.url))
])),
)
export default defineConfig({ export default defineConfig({
root: "src",
base: "/frontend",
build: { build: {
modulePreload: { modulePreload: {
polyfill: false polyfill: false

View File

@@ -8,7 +8,7 @@ use actix_web::{
use askama::Template; use askama::Template;
use routes::login::{route_get_login, route_post_login}; use routes::login::{route_get_login, route_post_login};
use rustical_store::{ use rustical_store::{
auth::{AuthenticationMiddleware, AuthenticationProvider}, auth::{AuthenticationMiddleware, AuthenticationProvider, User},
model::Calendar, model::Calendar,
CalendarStore, CalendarStore,
}; };
@@ -23,19 +23,39 @@ pub use config::FrontendConfig;
#[derive(Template)] #[derive(Template)]
#[template(path = "pages/user.html")] #[template(path = "pages/user.html")]
struct UserPage { struct UserPage {
pub owner: String, pub user_id: String,
pub calendars: Vec<Calendar>, pub calendars: Vec<Calendar>,
} }
async fn route_user<C: CalendarStore + ?Sized>( async fn route_user<C: CalendarStore + ?Sized>(
path: Path<String>, path: Path<String>,
store: Data<RwLock<C>>, store: Data<RwLock<C>>,
user: User,
) -> impl Responder { ) -> impl Responder {
let store = store.read().await; let store = store.read().await;
let owner = path.into_inner(); let user_id = path.into_inner();
UserPage { UserPage {
calendars: store.get_calendars(&user.id).await.unwrap(),
user_id: user.id,
}
}
#[derive(Template)]
#[template(path = "pages/calendar.html")]
struct CalendarPage {
owner: String,
calendar: Calendar,
}
async fn route_calendar<C: CalendarStore + ?Sized>(
path: Path<(String, String)>,
store: Data<RwLock<C>>,
) -> impl Responder {
let store = store.read().await;
let (owner, cid) = path.into_inner();
CalendarPage {
owner: owner.to_owned(), owner: owner.to_owned(),
calendars: store.get_calendars(&owner).await.unwrap(), calendar: store.get_calendar(&owner, &cid).await.unwrap(),
} }
} }
@@ -63,6 +83,10 @@ pub fn configure_frontend<AP: AuthenticationProvider, C: CalendarStore + ?Sized>
.service( .service(
web::resource("/user/{user}").route(web::method(Method::GET).to(route_user::<C>)), web::resource("/user/{user}").route(web::method(Method::GET).to(route_user::<C>)),
) )
.service(
web::resource("/user/{user}/{calendar}")
.route(web::method(Method::GET).to(route_calendar::<C>)),
)
.service( .service(
web::resource("/login") web::resource("/login")
.route(web::method(Method::GET).to(route_get_login)) .route(web::method(Method::GET).to(route_get_login))

View File

@@ -23,6 +23,7 @@ rstest_reuse = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
password-auth = { workspace = true } password-auth = { workspace = true }
actix-web = { workspace = true } actix-web = { workspace = true }
actix-session = { workspace = true }
actix-web-httpauth = { workspace = true } actix-web-httpauth = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
pbkdf2 = { workspace = true } pbkdf2 = { workspace = true }

View File

@@ -1,8 +1,9 @@
use super::AuthenticationProvider; use super::{AuthenticationProvider, User};
use actix_session::Session;
use actix_web::{ use actix_web::{
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform}, dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
http::header::Header, http::header::Header,
HttpMessage, FromRequest, HttpMessage,
}; };
use actix_web_httpauth::headers::authorization::{Authorization, Basic}; use actix_web_httpauth::headers::authorization::{Authorization, Basic};
use std::{ use std::{
@@ -77,6 +78,20 @@ where
} }
} }
} }
// Extract user from session cookie
if let Ok(session) = Session::extract(req.request()).await {
println!("There's a session!");
match session.get::<User>("user") {
Ok(Some(user)) => {
req.extensions_mut().insert(user);
}
Ok(None) => {}
Err(err) => {
dbg!(err);
}
};
}
service.call(req).await service.call(req).await
}) })
} }