fix: prevent infinite redirect loop for non-admin users on admin UI

When a non-admin user with a valid session cookie visited an admin-protected
route, auth_middleware redirected them to /login?next=<admin-path>, and
login_page immediately redirected them back because they were "logged in",
causing an infinite redirect loop.

Fix: only skip the login page when the logged-in user is also an admin.

https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
This commit is contained in:
Claude 2026-03-23 07:50:32 +00:00
parent 4aea0357b6
commit 812c81104a
No known key found for this signature in database

View file

@ -243,10 +243,23 @@ pub async fn login_page(
headers: HeaderMap, headers: HeaderMap,
Query(params): Query<NextParam>, Query(params): Query<NextParam>,
) -> Response { ) -> Response {
// Already logged in → redirect. // Already logged in as an admin → redirect.
if current_user_id(&state, &headers).await.is_some() { if let Some(uid) = current_user_id(&state, &headers).await {
let next = params.next.as_deref().map(|n| safe_redirect(n, &state.domain_suffix)).unwrap_or_else(|| "/".into()); let is_admin = if uid == "bootstrap" {
return Redirect::to(&next).into_response(); true
} else {
sqlx::query_scalar::<_, i64>("SELECT is_admin FROM users WHERE id = ?")
.bind(&uid)
.fetch_optional(&state.db)
.await
.unwrap_or(None)
.map(|v| v != 0)
.unwrap_or(false)
};
if is_admin {
let next = params.next.as_deref().map(|n| safe_redirect(n, &state.domain_suffix)).unwrap_or_else(|| "/".into());
return Redirect::to(&next).into_response();
}
} }
let next = params.next.map(|s| safe_redirect(&s, &state.domain_suffix)).unwrap_or_else(|| "/".into()); let next = params.next.map(|s| safe_redirect(&s, &state.domain_suffix)).unwrap_or_else(|| "/".into());
Html(login_html(&next, None)).into_response() Html(login_html(&next, None)).into_response()