refactor: simplify admin page auth with direct session lookup
Replace the private extract_user_from_session helper with inline session/user lookup, reusing the shared SESSION_COOKIE_NAME constant. Adds tracing instrumentation to the handler.
This commit is contained in:
parent
0bf30d3475
commit
b5d5949adf
1 changed files with 18 additions and 40 deletions
|
|
@ -7,8 +7,10 @@ use serde::Serialize;
|
||||||
use tower_cookies::Cookies;
|
use tower_cookies::Cookies;
|
||||||
use tracing::{error, warn};
|
use tracing::{error, warn};
|
||||||
|
|
||||||
|
use crate::application::auth::SESSION_COOKIE_NAME;
|
||||||
use crate::application::routes::render_html;
|
use crate::application::routes::render_html;
|
||||||
use crate::application::state::AppState;
|
use crate::application::state::AppState;
|
||||||
|
use crate::infrastructure::auth::hash_token;
|
||||||
|
|
||||||
// --- View types ---
|
// --- View types ---
|
||||||
|
|
||||||
|
|
@ -77,18 +79,29 @@ struct AdminTemplate {
|
||||||
|
|
||||||
// --- Page handler ---
|
// --- Page handler ---
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(state, cookies))]
|
||||||
pub(crate) async fn admin_page(
|
pub(crate) async fn admin_page(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
cookies: Cookies,
|
cookies: Cookies,
|
||||||
) -> Result<Response, StatusCode> {
|
) -> Result<Response, StatusCode> {
|
||||||
if !crate::application::routes::is_authenticated(&state, &cookies).await {
|
// Web page: redirect to login instead of returning 401
|
||||||
|
let Some(cookie) = cookies.get(SESSION_COOKIE_NAME) else {
|
||||||
|
return Ok(Redirect::to("/login").into_response());
|
||||||
|
};
|
||||||
|
let session_hash = hash_token(cookie.value());
|
||||||
|
let session = state
|
||||||
|
.session_repo
|
||||||
|
.get_by_token_hash(&session_hash)
|
||||||
|
.await
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
if session.is_expired() {
|
||||||
return Ok(Redirect::to("/login").into_response());
|
return Ok(Redirect::to("/login").into_response());
|
||||||
}
|
}
|
||||||
|
let auth_user = state
|
||||||
// We need the authenticated user for repo queries — re-extract from session
|
.user_repo
|
||||||
let auth_user = extract_user_from_session(&state, &cookies)
|
.get(session.user_id)
|
||||||
.await
|
.await
|
||||||
.ok_or(StatusCode::UNAUTHORIZED)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
let passkeys = state
|
let passkeys = state
|
||||||
.passkey_repo
|
.passkey_repo
|
||||||
|
|
@ -149,38 +162,3 @@ pub(crate) async fn admin_page(
|
||||||
|
|
||||||
render_html(template).map(IntoResponse::into_response)
|
render_html(template).map(IntoResponse::into_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Helpers ---
|
|
||||||
|
|
||||||
async fn extract_user_from_session(
|
|
||||||
state: &AppState,
|
|
||||||
cookies: &Cookies,
|
|
||||||
) -> Option<crate::domain::users::User> {
|
|
||||||
let cookie = cookies.get("brewlog_session")?;
|
|
||||||
let session_token = cookie.value();
|
|
||||||
let session_token_hash = crate::infrastructure::auth::hash_token(session_token);
|
|
||||||
|
|
||||||
let session = match state
|
|
||||||
.session_repo
|
|
||||||
.get_by_token_hash(&session_token_hash)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(s) => s,
|
|
||||||
Err(err) => {
|
|
||||||
warn!(error = %err, "session lookup failed on admin page");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if session.is_expired() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match state.user_repo.get(session.user_id).await {
|
|
||||||
Ok(user) => Some(user),
|
|
||||||
Err(err) => {
|
|
||||||
warn!(error = %err, user_id = %session.user_id, "user lookup failed for valid session");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue