feat: Implement flexible authentication supporting JWT, OIDC, and session modes, alongside new configuration options and refactored auth layer setup.
This commit is contained in:
@@ -5,34 +5,29 @@ use axum::{
|
||||
extract::{Path, Query, State},
|
||||
http::StatusCode,
|
||||
};
|
||||
use axum_login::AuthSession;
|
||||
use uuid::Uuid;
|
||||
use validator::Validate;
|
||||
|
||||
use axum_login::AuthUser;
|
||||
use notes_domain::{
|
||||
CreateNoteRequest as DomainCreateNote, NoteTitle, TagName,
|
||||
UpdateNoteRequest as DomainUpdateNote,
|
||||
};
|
||||
|
||||
use crate::auth::AuthBackend;
|
||||
use crate::dto::{CreateNoteRequest, ListNotesQuery, NoteResponse, SearchQuery, UpdateNoteRequest};
|
||||
use crate::error::{ApiError, ApiResult};
|
||||
use crate::state::AppState;
|
||||
use crate::{
|
||||
dto::{CreateNoteRequest, ListNotesQuery, NoteResponse, SearchQuery, UpdateNoteRequest},
|
||||
extractors::CurrentUser,
|
||||
};
|
||||
|
||||
/// List notes with optional filtering
|
||||
/// GET /api/v1/notes
|
||||
pub async fn list_notes(
|
||||
State(state): State<AppState>,
|
||||
auth: AuthSession<AuthBackend>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
Query(query): Query<ListNotesQuery>,
|
||||
) -> ApiResult<Json<Vec<NoteResponse>>> {
|
||||
let user = auth
|
||||
.user
|
||||
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
|
||||
"Login required".to_string(),
|
||||
)))?;
|
||||
let user_id = user.id();
|
||||
let user_id = user.id;
|
||||
|
||||
// Build the filter, looking up tag_id by name if needed
|
||||
let mut filter = notes_domain::NoteFilter::new();
|
||||
@@ -59,15 +54,10 @@ pub async fn list_notes(
|
||||
/// POST /api/v1/notes
|
||||
pub async fn create_note(
|
||||
State(state): State<AppState>,
|
||||
auth: AuthSession<AuthBackend>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
Json(payload): Json<CreateNoteRequest>,
|
||||
) -> ApiResult<(StatusCode, Json<NoteResponse>)> {
|
||||
let user = auth
|
||||
.user
|
||||
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
|
||||
"Login required".to_string(),
|
||||
)))?;
|
||||
let user_id = user.id();
|
||||
let user_id = user.id;
|
||||
|
||||
// Validate input
|
||||
payload
|
||||
@@ -113,15 +103,10 @@ pub async fn create_note(
|
||||
/// GET /api/v1/notes/:id
|
||||
pub async fn get_note(
|
||||
State(state): State<AppState>,
|
||||
auth: AuthSession<AuthBackend>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> ApiResult<Json<NoteResponse>> {
|
||||
let user = auth
|
||||
.user
|
||||
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
|
||||
"Login required".to_string(),
|
||||
)))?;
|
||||
let user_id = user.id();
|
||||
let user_id = user.id;
|
||||
|
||||
let note = state.note_service.get_note(id, user_id).await?;
|
||||
|
||||
@@ -132,16 +117,11 @@ pub async fn get_note(
|
||||
/// PATCH /api/v1/notes/:id
|
||||
pub async fn update_note(
|
||||
State(state): State<AppState>,
|
||||
auth: AuthSession<AuthBackend>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
Path(id): Path<Uuid>,
|
||||
Json(payload): Json<UpdateNoteRequest>,
|
||||
) -> ApiResult<Json<NoteResponse>> {
|
||||
let user = auth
|
||||
.user
|
||||
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
|
||||
"Login required".to_string(),
|
||||
)))?;
|
||||
let user_id = user.id();
|
||||
let user_id = user.id;
|
||||
|
||||
// Validate input
|
||||
payload
|
||||
@@ -195,15 +175,10 @@ pub async fn update_note(
|
||||
/// DELETE /api/v1/notes/:id
|
||||
pub async fn delete_note(
|
||||
State(state): State<AppState>,
|
||||
auth: AuthSession<AuthBackend>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> ApiResult<StatusCode> {
|
||||
let user = auth
|
||||
.user
|
||||
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
|
||||
"Login required".to_string(),
|
||||
)))?;
|
||||
let user_id = user.id();
|
||||
let user_id = user.id;
|
||||
|
||||
state.note_service.delete_note(id, user_id).await?;
|
||||
|
||||
@@ -214,15 +189,10 @@ pub async fn delete_note(
|
||||
/// GET /api/v1/notes/search
|
||||
pub async fn search_notes(
|
||||
State(state): State<AppState>,
|
||||
auth: AuthSession<AuthBackend>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
Query(query): Query<SearchQuery>,
|
||||
) -> ApiResult<Json<Vec<NoteResponse>>> {
|
||||
let user = auth
|
||||
.user
|
||||
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
|
||||
"Login required".to_string(),
|
||||
)))?;
|
||||
let user_id = user.id();
|
||||
let user_id = user.id;
|
||||
|
||||
let notes = state.note_service.search_notes(user_id, &query.q).await?;
|
||||
let response: Vec<NoteResponse> = notes.into_iter().map(NoteResponse::from).collect();
|
||||
@@ -234,15 +204,10 @@ pub async fn search_notes(
|
||||
/// GET /api/v1/notes/:id/versions
|
||||
pub async fn list_note_versions(
|
||||
State(state): State<AppState>,
|
||||
auth: AuthSession<AuthBackend>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> ApiResult<Json<Vec<crate::dto::NoteVersionResponse>>> {
|
||||
let user = auth
|
||||
.user
|
||||
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
|
||||
"Login required".to_string(),
|
||||
)))?;
|
||||
let user_id = user.id();
|
||||
let user_id = user.id;
|
||||
|
||||
let versions = state.note_service.list_note_versions(id, user_id).await?;
|
||||
let response: Vec<crate::dto::NoteVersionResponse> = versions
|
||||
@@ -260,15 +225,10 @@ pub async fn list_note_versions(
|
||||
#[cfg(feature = "smart-features")]
|
||||
pub async fn get_related_notes(
|
||||
State(state): State<AppState>,
|
||||
auth: AuthSession<AuthBackend>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> ApiResult<Json<Vec<crate::dto::NoteLinkResponse>>> {
|
||||
let user = auth
|
||||
.user
|
||||
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
|
||||
"Login required".to_string(),
|
||||
)))?;
|
||||
let user_id = user.id();
|
||||
let user_id = user.id;
|
||||
|
||||
// Verify access to the source note
|
||||
state.note_service.get_note(id, user_id).await?;
|
||||
|
||||
Reference in New Issue
Block a user