Portal-Login: E-Mail-Code für Mitarbeiter mit 2FA
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
25f15c0ecb
commit
9b14a74fcc
6 files changed
+304
-36
No files matched your search
@@ -548,6 +548,10 @@ async function initLoginPage() {
|
||||
password: document.getElementById('password').value,
|
||||
}),
|
||||
})
|
||||
if (result.mfaRequired) {
|
||||
showMfaStep(result.email)
|
||||
return
|
||||
}
|
||||
if (result.role === 'admin') {
|
||||
window.location.href = adminLoginTarget()
|
||||
return
|
||||
@@ -568,6 +572,59 @@ async function initLoginPage() {
|
||||
})
|
||||
}
|
||||
|
||||
/* Mitarbeiter-2FA: Code aus der E-Mail (POST /api/auth/login/mfa) */
|
||||
function showMfaStep(maskedEmail) {
|
||||
const loginForm = document.getElementById('login-form')
|
||||
const form = document.getElementById('mfa-form')
|
||||
const input = document.getElementById('mfa-code')
|
||||
const errorEl = document.getElementById('mfa-error')
|
||||
const btn = document.getElementById('mfa-btn')
|
||||
const resend = document.getElementById('mfa-resend')
|
||||
loginForm?.classList.add('hidden')
|
||||
form?.classList.remove('hidden')
|
||||
document.getElementById('mfa-hint').textContent = `Wir haben dir einen Code an ${maskedEmail} geschickt.`
|
||||
input?.focus()
|
||||
|
||||
form?.addEventListener('submit', async (e) => {
|
||||
e.preventDefault()
|
||||
if (btn.disabled) return
|
||||
hideError(errorEl)
|
||||
btn.disabled = true
|
||||
btn.classList.add('is-loading')
|
||||
try {
|
||||
await api('/api/auth/login/mfa', { method: 'POST', body: JSON.stringify({ otp: input.value.trim() }) })
|
||||
window.location.href = adminLoginTarget()
|
||||
} catch (err) {
|
||||
if (err.status === 410) {
|
||||
window.location.href = `/login.html?error=${encodeURIComponent(err.message)}`
|
||||
return
|
||||
}
|
||||
showError(errorEl, err.message)
|
||||
input.select()
|
||||
} finally {
|
||||
btn.disabled = false
|
||||
btn.classList.remove('is-loading')
|
||||
}
|
||||
})
|
||||
|
||||
resend?.addEventListener('click', async () => {
|
||||
hideError(errorEl)
|
||||
resend.disabled = true
|
||||
try {
|
||||
await api('/api/auth/login/mfa/resend', { method: 'POST' })
|
||||
document.getElementById('mfa-hint').textContent = `Neuer Code ist unterwegs an ${maskedEmail}.`
|
||||
} catch (err) {
|
||||
if (err.status === 410) {
|
||||
window.location.href = `/login.html?error=${encodeURIComponent(err.message)}`
|
||||
return
|
||||
}
|
||||
showError(errorEl, err.message)
|
||||
} finally {
|
||||
resend.disabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------- View-as --- */
|
||||
function renderViewAsBanner(me) {
|
||||
const banner = document.getElementById('viewas-banner')
|
||||
|
||||
@@ -647,3 +647,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Mitarbeiter-2FA: Code-Schritt */
|
||||
#mfa-form.hidden { display: none; }
|
||||
.mfa-hint { margin: 0 0 4px; text-align: center; }
|
||||
#mfa-code { letter-spacing: 0.3em; font-variant-numeric: tabular-nums; }
|
||||
.mfa-actions { margin-top: 12px; }
|
||||
.mfa-link {
|
||||
background: none;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -72,6 +72,31 @@
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
<!-- Mitarbeiter mit 2FA: zweiter Schritt, Code aus der E-Mail -->
|
||||
<form id="mfa-form" class="login-form hidden" novalidate>
|
||||
<p id="mfa-hint" class="login-hint mfa-hint"></p>
|
||||
<label class="auth-label" for="mfa-code">Code aus der E-Mail</label>
|
||||
<input
|
||||
class="auth-input"
|
||||
type="text"
|
||||
name="otp"
|
||||
id="mfa-code"
|
||||
inputmode="numeric"
|
||||
autocomplete="one-time-code"
|
||||
maxlength="6"
|
||||
pattern="[0-9]{6}"
|
||||
enterkeyhint="go"
|
||||
>
|
||||
<p id="mfa-error" class="error hidden"></p>
|
||||
<button type="submit" id="mfa-btn" class="auth-button login-button">
|
||||
<span class="button-label">Anmelden</span>
|
||||
</button>
|
||||
<p class="login-hint mfa-actions">
|
||||
<button type="button" id="mfa-resend" class="mfa-link">Code erneut senden</button>
|
||||
·
|
||||
<a href="/login.html" class="mfa-link">Abbrechen</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<p class="login-hint">
|
||||
Zugangsdaten erhältst du von Webklar. Dein Passwort kannst du nach der Anmeldung selbst ändern (Profilbild oben rechts, „Passwort ändern“).
|
||||
|
||||
Reference in new issue
Block a user