fix: break infinite redirect for non-admin users on admin UI
Root cause: auth_middleware redirected all non-admins (including logged-in ones) to /login, and login_page redirected logged-in users back — a loop. Fix: - auth_middleware now distinguishes unauthenticated (→ /login?next=) from logged-in-but-not-admin (→ /denied), breaking the loop entirely - /denied page's "sign in with a different account" link now goes to /logout first, so clicking it clears the session before the login form appears The login_page auto-redirect for logged-in users is restored, which is required for the Caddy forward_auth flow (deployed apps redirecting through /login?next=<app-url>). https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
This commit is contained in:
parent
812c81104a
commit
1671aaf8e8
1 changed files with 26 additions and 34 deletions
|
|
@ -96,28 +96,33 @@ pub async fn auth_middleware(
|
||||||
|
|
||||||
let user_id = current_user_id(&state, request.headers()).await;
|
let user_id = current_user_id(&state, request.headers()).await;
|
||||||
|
|
||||||
let is_admin = match user_id {
|
let path = request
|
||||||
None => false,
|
.uri()
|
||||||
Some(uid) => {
|
.path_and_query()
|
||||||
sqlx::query_scalar::<_, i64>("SELECT is_admin FROM users WHERE id = ?")
|
.map(|p| p.as_str())
|
||||||
.bind(&uid)
|
.unwrap_or("/");
|
||||||
.fetch_optional(&state.db)
|
|
||||||
.await
|
let uid = match user_id {
|
||||||
.unwrap_or(None)
|
None => {
|
||||||
.map(|v| v != 0)
|
// Not logged in → send to login with return path.
|
||||||
.unwrap_or(false)
|
return Redirect::to(&format!("/login?next={}", safe_path(path))).into_response();
|
||||||
}
|
}
|
||||||
|
Some(uid) => uid,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let is_admin = 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 {
|
if is_admin {
|
||||||
next.run(request).await
|
next.run(request).await
|
||||||
} else {
|
} else {
|
||||||
let path = request
|
// Logged in but not an admin → access denied, no redirect loop.
|
||||||
.uri()
|
Redirect::to("/denied").into_response()
|
||||||
.path_and_query()
|
|
||||||
.map(|p| p.as_str())
|
|
||||||
.unwrap_or("/");
|
|
||||||
Redirect::to(&format!("/login?next={}", safe_path(path))).into_response()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,23 +248,10 @@ pub async fn login_page(
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
Query(params): Query<NextParam>,
|
Query(params): Query<NextParam>,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
// Already logged in as an admin → redirect.
|
// Already logged in → redirect.
|
||||||
if let Some(uid) = current_user_id(&state, &headers).await {
|
if current_user_id(&state, &headers).await.is_some() {
|
||||||
let is_admin = if uid == "bootstrap" {
|
let next = params.next.as_deref().map(|n| safe_redirect(n, &state.domain_suffix)).unwrap_or_else(|| "/".into());
|
||||||
true
|
return Redirect::to(&next).into_response();
|
||||||
} 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()
|
||||||
|
|
@ -361,7 +353,7 @@ a{{color:#818cf8}}</style></head><body>
|
||||||
<h1>Access denied</h1>
|
<h1>Access denied</h1>
|
||||||
<p>You do not have access to <strong>{app}</strong>.</p>
|
<p>You do not have access to <strong>{app}</strong>.</p>
|
||||||
<p>Contact your administrator to request access.</p>
|
<p>Contact your administrator to request access.</p>
|
||||||
<a href="/login">← Sign in with a different account</a>
|
<a href="/logout">← Sign in with a different account</a>
|
||||||
</div></body></html>"#
|
</div></body></html>"#
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue