Introducing the 'player' role turned 'logged-in' into 'logged-in but possibly
untrusted', but the admin router only gated content routes (dashboard, posts,
wiki, uploads) by isLoggedIn — so a player session could reach editor-tier
endpoints. Fixes:
- Backend: requireRole('admin','editor','moderator') at the admin router base;
players now 403 on all /admin/* and use /player instead.
- Client: RequireAuth redirects a signed-in player to /account (mirrors
RequirePlayer).
- Both login pages redirect by role after auth (player -> /account, staff ->
/admin) so you land in the right shell whichever door you used.
Verified live: player token 403s on /admin/dashboard + /admin/users, 200s on
/player/account; browser click-through confirms a player at /admin and at
/admin/login both land on /account. 134 server tests green; client builds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rao86n5cXpwAyjdBFEshV
26 lines
855 B
JavaScript
26 lines
855 B
JavaScript
import { Navigate, useLocation } from 'react-router-dom'
|
|
import { useAuth } from '../contexts/AuthContext.jsx'
|
|
|
|
// Gate for /admin/* — redirects to the login screen when not authenticated, and
|
|
// bounces a signed-in player to their own portal (the admin API 403s them anyway;
|
|
// this keeps the UI honest and mirrors RequirePlayer).
|
|
export default function RequireAuth({ children }) {
|
|
const { user, loading } = useAuth()
|
|
const location = useLocation()
|
|
|
|
if (loading) {
|
|
return (
|
|
<div style={{ minHeight: '100vh', display: 'grid', placeItems: 'center', background: 'var(--bg-deep)' }}>
|
|
<span className="spin" />
|
|
</div>
|
|
)
|
|
}
|
|
if (!user) {
|
|
return <Navigate to="/admin/login" state={{ from: location }} replace />
|
|
}
|
|
if (user.role === 'player') {
|
|
return <Navigate to="/account" replace />
|
|
}
|
|
return children
|
|
}
|