auth: gate SPA boot on /api/auth/me, add user badge and logout
This commit is contained in:
parent
939bf38b66
commit
2d8d58a9ef
@ -1,3 +1,47 @@
|
||||
// -------------------------------------------------------------------------
|
||||
// Auth gate: runs before the main app IIFE bootstraps. If the user is not
|
||||
// authenticated, we redirect to /login.html (or /setup.html when the backend
|
||||
// indicates the initial setup is still required) and abort further init.
|
||||
// -------------------------------------------------------------------------
|
||||
(async function authGate() {
|
||||
try {
|
||||
const r = await fetch('/api/auth/me', { credentials: 'same-origin' });
|
||||
if (r.status === 401) {
|
||||
const setup = await fetch('/api/auth/setup-required').then(function (x) { return x.json(); }).catch(function () { return { setup_required: false }; });
|
||||
window.location.replace(setup.setup_required ? '/setup.html' : '/login.html');
|
||||
return;
|
||||
}
|
||||
if (!r.ok) return;
|
||||
const me = await r.json();
|
||||
window.__clearviewUser = me;
|
||||
renderUserBadge(me);
|
||||
if (me.role !== 'admin') {
|
||||
const usersLink = document.querySelector('[data-route="users"]');
|
||||
if (usersLink) usersLink.style.display = 'none';
|
||||
}
|
||||
} catch (e) {
|
||||
window.location.replace('/login.html');
|
||||
}
|
||||
})();
|
||||
|
||||
function renderUserBadge(me) {
|
||||
const slot = document.getElementById('userBadge');
|
||||
if (!slot) return;
|
||||
slot.innerHTML = '';
|
||||
const wrap = document.createElement('span');
|
||||
wrap.className = 'user-badge';
|
||||
wrap.append(document.createTextNode(me.username + ' (' + me.role + ')'));
|
||||
const btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.textContent = 'Sign out';
|
||||
btn.addEventListener('click', async function () {
|
||||
await fetch('/api/auth/logout', { method: 'POST', credentials: 'same-origin' });
|
||||
window.location.replace('/login.html');
|
||||
});
|
||||
wrap.append(btn);
|
||||
slot.append(wrap);
|
||||
}
|
||||
|
||||
(function () {
|
||||
const state = {
|
||||
selectedJobId: null,
|
||||
@ -113,7 +157,11 @@
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
async function requestJson(url, options) {
|
||||
const response = await fetch(url, options);
|
||||
const response = await fetch(url, Object.assign({ credentials: 'same-origin' }, options || {}));
|
||||
if (response.status === 401) {
|
||||
window.location.replace('/login.html');
|
||||
throw new Error('unauthenticated');
|
||||
}
|
||||
if (!response.ok) {
|
||||
let detail = response.statusText;
|
||||
try {
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
<div class="nav-section">Entra</div>
|
||||
<a href="#/scan/entra" class="nav-link" data-route="scan-entra">New Entra Scan</a>
|
||||
|
||||
<a href="#/users" class="nav-link" data-route="users">Users</a>
|
||||
<div class="nav-spacer"></div>
|
||||
<a href="#/tenants" class="nav-link" data-route="tenants">Tenants</a>
|
||||
<a href="#/settings" class="nav-link" data-route="settings">Settings</a>
|
||||
@ -46,6 +47,7 @@
|
||||
<div class="content-title" id="contentTitle">Dashboard</div>
|
||||
<div class="content-actions">
|
||||
<button id="refreshJobsBtn" class="btn btn-outline" type="button">Refresh</button>
|
||||
<div class="header-user" id="userBadge"></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user