Admin: Login-Link mit window.location.origin statt Server-Host

- Backend gibt nur Token zurück statt fertigen Link
- Frontend baut Link via window.location.origin zusammen
- Zeigt korrekte Domain/Port statt internes http://127.0.0.1

Backend:
- AdminEndpoint: POST /api/admin/users/{userId}/login-link gibt { token }
- AuthEndpoint: GET /api/auth/autologin?token=xxx setzt Cookie + redirect
- AuthMiddleware: autologin-Route von Auth ausgenommen

Frontend:
- api.js: apiAdminGetLoginLink() Funktion
- admin-page.js: Login-as-User Button → Login-Link Button mit Modal
- form.css: Styling für Login-Link Modal
This commit is contained in:
Meleki committed 2026-03-06 14:35:01 +01:00
1 parent eeecd3da62
commit 1b9cc29421
6 files changed
+184 -17

No files matched your search

+77 -16
View File
@@ -79,16 +79,16 @@ registerPage('admin', {
});
actions.appendChild(editBtn);
// Login as User (nicht für sich selbst)
// Login-Link + Löschen (nicht für sich selbst)
if (user.userId !== currentUser.userId) {
var loginAsBtn = document.createElement('button');
loginAsBtn.className = 'icon-btn';
loginAsBtn.title = 'Als ' + (user.displayName || user.username) + ' anmelden';
loginAsBtn.innerHTML = '<i class="fa fa-sign-in"></i>';
loginAsBtn.addEventListener('click', function() {
impersonateUser(user);
var linkBtn = document.createElement('button');
linkBtn.className = 'icon-btn';
linkBtn.title = 'Login-Link generieren';
linkBtn.innerHTML = '<i class="fa fa-link"></i>';
linkBtn.addEventListener('click', function() {
generateLoginLink(user);
});
actions.appendChild(loginAsBtn);
actions.appendChild(linkBtn);
var deleteBtn = document.createElement('button');
deleteBtn.className = 'icon-btn';
@@ -146,20 +146,81 @@ registerPage('admin', {
}
}
async function impersonateUser(user) {
if (!confirm('Als "' + (user.displayName || user.username) + '" anmelden?\n\nDu wirst abgemeldet und als dieser Benutzer eingeloggt.')) {
return;
}
async function generateLoginLink(user) {
try {
await apiAdminImpersonate(user.userId);
// Seite neu laden, damit der neue User-Kontext geladen wird
location.reload();
var result = await apiAdminGetLoginLink(user.userId);
var link = window.location.origin + '/api/auth/autologin?token=' + result.token;
showLoginLinkModal(user, link);
} catch (err) {
showPageMessage(err.message, true);
}
}
function showLoginLinkModal(user, link) {
// Entferne vorherigen Modal falls vorhanden
var existing = document.querySelector('.login-link-overlay');
if (existing) existing.remove();
var overlay = document.createElement('div');
overlay.className = 'login-link-overlay';
var modal = document.createElement('div');
modal.className = 'login-link-modal';
var title = document.createElement('h3');
title.textContent = 'Login-Link für ' + (user.displayName || user.username);
var desc = document.createElement('p');
desc.className = 'login-link-desc';
desc.textContent = 'Dieser Link loggt automatisch als dieser Benutzer ein. Teile ihn nur mit vertrauenswürdigen Personen.';
var inputRow = document.createElement('div');
inputRow.className = 'login-link-input-row';
var input = document.createElement('input');
input.type = 'text';
input.readOnly = true;
input.value = link;
input.className = 'login-link-input';
var copyBtn = document.createElement('button');
copyBtn.className = 'btn btn-primary';
copyBtn.innerHTML = '<i class="fa fa-copy"></i> Kopieren';
copyBtn.addEventListener('click', function() {
navigator.clipboard.writeText(link).then(function() {
copyBtn.innerHTML = '<i class="fa fa-check"></i> Kopiert!';
setTimeout(function() {
copyBtn.innerHTML = '<i class="fa fa-copy"></i> Kopieren';
}, 2000);
});
});
inputRow.appendChild(input);
inputRow.appendChild(copyBtn);
var closeBtn = document.createElement('button');
closeBtn.className = 'btn';
closeBtn.textContent = 'Schließen';
closeBtn.addEventListener('click', function() {
overlay.remove();
});
modal.appendChild(title);
modal.appendChild(desc);
modal.appendChild(inputRow);
modal.appendChild(closeBtn);
overlay.appendChild(modal);
overlay.addEventListener('click', function(e) {
if (e.target === overlay) overlay.remove();
});
document.body.appendChild(overlay);
// Input selektieren für einfaches Kopieren
input.select();
}
// ── Event-Listener ──
// Default Path Browse