feat: add app-level authentication foundation

This commit is contained in:
a.tolmachev
2026-03-30 23:47:09 +03:00
parent 91854a4153
commit ab2e603997
42 changed files with 1624 additions and 236 deletions
+52
View File
@@ -0,0 +1,52 @@
use axum::{Json, extract::State, http::StatusCode, response::IntoResponse};
use axum_extra::extract::cookie::CookieJar;
use crate::{
auth::{cleared_session_cookie, extract_session_token, session_cookie},
error::ApiError,
service::LoginPayload,
state::AppState,
};
pub async fn login(
State(state): State<AppState>,
jar: CookieJar,
Json(payload): Json<LoginPayload>,
) -> Result<impl IntoResponse, ApiError> {
let (session_data, session) = state.service.login(payload).await?;
let cookie_value = format!(
"{}.{}",
session_data.session_id.as_str(),
session_data.value
);
let jar = jar.add(session_cookie(state.service.auth_settings(), &cookie_value));
Ok((jar, Json(serde_json::json!(session))))
}
pub async fn logout(
State(state): State<AppState>,
jar: CookieJar,
) -> Result<impl IntoResponse, ApiError> {
if let Some((session_id, session_value)) = extract_session_token(&jar) {
state.service.logout(&session_id, &session_value).await?;
}
let jar = jar.remove(cleared_session_cookie(state.service.auth_settings()));
Ok((jar, StatusCode::NO_CONTENT))
}
pub async fn get_session(
State(state): State<AppState>,
jar: CookieJar,
) -> Result<Json<serde_json::Value>, ApiError> {
let (session_id, session_value) = extract_session_token(&jar)
.ok_or_else(|| ApiError::unauthorized("authentication required"))?;
let session = state
.service
.session_response(&session_id, &session_value)
.await?
.ok_or_else(|| ApiError::unauthorized("session is invalid or expired"))?;
Ok(Json(serde_json::json!(session)))
}
+15 -4
View File
@@ -1,25 +1,36 @@
use axum::{
Json,
Extension, Json,
extract::{Path, State},
};
use serde_json::{Value, json};
use crate::{
auth::AuthenticatedSession,
error::ApiError,
service::{UpdateWorkspacePayload, WorkspacePayload},
state::AppState,
};
pub async fn list_workspaces(State(state): State<AppState>) -> Result<Json<Value>, ApiError> {
let items = state.service.list_workspaces().await?;
pub async fn list_workspaces(
State(state): State<AppState>,
Extension(session): Extension<AuthenticatedSession>,
) -> Result<Json<Value>, ApiError> {
let items = state
.service
.list_workspaces_for_user(&session.user.id)
.await?;
Ok(Json(json!({ "items": items })))
}
pub async fn create_workspace(
State(state): State<AppState>,
Extension(session): Extension<AuthenticatedSession>,
Json(payload): Json<WorkspacePayload>,
) -> Result<Json<Value>, ApiError> {
let workspace = state.service.create_workspace(payload).await?;
let workspace = state
.service
.create_workspace(&session.user.id, payload)
.await?;
Ok(Json(json!(workspace)))
}