mirror of
https://github.com/LD-Reborn/Berufsschule_HAM.git
synced 2025-12-19 22:41:55 +00:00
Added re-authentication modal
This commit is contained in:
@@ -166,6 +166,7 @@ public class HomeController : Controller
|
||||
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
Response.StatusCode = 500;
|
||||
switch (authenticationResult.AuthenticationState)
|
||||
{
|
||||
case UserNotAuthenticatedReason.InvalidCredentials:
|
||||
@@ -198,4 +199,18 @@ public class HomeController : Controller
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpGet("RemainingTime")]
|
||||
public async Task<IActionResult> GetRemainingSessionTime()
|
||||
{
|
||||
var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
if (!result.Succeeded || result.Properties?.ExpiresUtc == null)
|
||||
return Json(new { remainingMinutes = 0 });
|
||||
|
||||
var remaining = result.Properties.ExpiresUtc.Value - DateTimeOffset.UtcNow;
|
||||
return Json(new { remainingMinutes = (int) Math.Ceiling(remaining.TotalMinutes) });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,12 +19,6 @@
|
||||
<data name="Login" xml:space="preserve">
|
||||
<value>Anmelden</value>
|
||||
</data>
|
||||
<data name="Username" xml:space="preserve">
|
||||
<value>Benutzername</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>Passwort</value>
|
||||
</data>
|
||||
<data name="Invalid login credentials" xml:space="preserve">
|
||||
<value>Ungültige Anmeldedaten</value>
|
||||
</data>
|
||||
|
||||
@@ -61,4 +61,28 @@
|
||||
<data name="Admin settings" xml:space="preserve">
|
||||
<value>Administration</value>
|
||||
</data>
|
||||
<data name="Extend session duration" xml:space="preserve">
|
||||
<value>Sitzung verlängern</value>
|
||||
</data>
|
||||
<data name="The session expires soon." xml:space="preserve">
|
||||
<value>Die Sitzung läuft bald ab.</value>
|
||||
</data>
|
||||
<data name="Please authenticate to continue without losing data." xml:space="preserve">
|
||||
<value>Bitte authentifizieren Sie sich, um fortzufahren, ohne Daten zu verlieren.</value>
|
||||
</data>
|
||||
<data name="Re-authenticate" xml:space="preserve">
|
||||
<value>Authentifizieren</value>
|
||||
</data>
|
||||
<data name="Invalid login credentials" xml:space="preserve">
|
||||
<value>Ungültige Anmeldedaten</value>
|
||||
</data>
|
||||
<data name="Your account has been locked. Wait a few minutes or ask an administrator to unlock you" xml:space="preserve">
|
||||
<value>Ihr Konto wurde gesperrt. Warten Sie einige Minuten oder bitten Sie einen Administrator, die Sperre aufzuheben.</value>
|
||||
</data>
|
||||
<data name="You are not authorized for login. Ask an administrator to authorize you." xml:space="preserve">
|
||||
<value>Sie sind nicht zur Anmeldung berechtigt. Bitten Sie einen Administrator, Ihnen die Berechtigung zu erteilen.</value>
|
||||
</data>
|
||||
<data name="Hell froze over. Make a screenshot and send it to an administrator." xml:space="preserve">
|
||||
<value>Die Hölle ist zugefroren. Machen Sie einen Screenshot und senden Sie ihn an einen Administrator.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
25
src/Resources/Views.Shared._Login.de.resx
Normal file
25
src/Resources/Views.Shared._Login.de.resx
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, ...</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, ...</value>
|
||||
</resheader>
|
||||
|
||||
<data name="Login" xml:space="preserve">
|
||||
<value>Anmelden</value>
|
||||
</data>
|
||||
<data name="Username" xml:space="preserve">
|
||||
<value>Benutzername</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>Passwort</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -15,17 +15,5 @@
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<form method="post" action="/Home/Login" class="mt-4" style="max-width: 400px; margin: auto;">
|
||||
<div class="form-group mb-3">
|
||||
<label for="username" class="form-label">@T["Username"]</label>
|
||||
<input autofocus type="text" class="form-control" id="username" name="username" autocomplete="username" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="password" class="form-label">@T["Password"]</label>
|
||||
<input type="password" class="form-control" id="password" name="password" autocomplete="current-password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary w-100">@T["Login"]</button>
|
||||
</form>
|
||||
<partial name="_Login" />
|
||||
</div>
|
||||
|
||||
@@ -139,6 +139,88 @@
|
||||
© 2025 - Berufsschule_HAM
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Re-authentication Modal -->
|
||||
<div class="modal fade" id="reAuthModal" tabindex="-1" aria-labelledby="reAuthModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-info text-dark">
|
||||
<h3 class="modal-title" id="detailModalLabel">@T["Extend session duration"]</h3>
|
||||
<button type="button" class="btn-close btn-close-white" style="filter: invert(0);" aria-label="Close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form id="reAuthForm">
|
||||
<div class="modal-body">
|
||||
<p id="reAuthModalLabel" class="text-center">@T["The session expires soon."]<br/>@T["Please authenticate to continue without losing data."]</p>
|
||||
<div class="mb-3">
|
||||
<label for="reAuthUsername" class="form-label">@T["Username"]</label>
|
||||
<input type="text" class="form-control" id="reAuthUsername" name="Username"
|
||||
value="@User.Identity?.Name" readonly />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="reAuthPassword" class="form-label">@T["Password"]</label>
|
||||
<input type="password" class="form-control" id="reAuthPassword" name="Password" required />
|
||||
</div>
|
||||
<div class="alert alert-danger d-none" id="reAuthError"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">@T["Re-authenticate"]</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Flag so modal only opens once
|
||||
window.reAuthModalOpen = false;
|
||||
|
||||
function openReAuthModal() {
|
||||
window.reAuthModalOpen = true;
|
||||
const reAuthModal = new bootstrap.Modal(document.getElementById('reAuthModal'));
|
||||
reAuthModal.show();
|
||||
}
|
||||
|
||||
function scheduleReAuthModal() {
|
||||
fetch('/Home/RemainingTime')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
let remainingMinutesThreshold = 20;
|
||||
let remainingMinutes = data.remainingMinutes;
|
||||
let triggerMinutes = Math.max(0, remainingMinutes - remainingMinutesThreshold);
|
||||
let triggerMs = triggerMinutes * 60 * 1000;
|
||||
|
||||
setTimeout(() => {
|
||||
if (!window.reAuthModalOpen) {
|
||||
openReAuthModal();
|
||||
}
|
||||
}, triggerMs);
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
scheduleReAuthModal();
|
||||
|
||||
$('#reAuthForm').on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
const formData = $(this).serialize();
|
||||
$.post('/Home/Login', formData)
|
||||
.done(function () {
|
||||
window.reAuthModalOpen = false;
|
||||
$('#reAuthModal').modal('hide');
|
||||
})
|
||||
.fail(function (data) {
|
||||
console.log(data);
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(data.responseText, 'text/html');
|
||||
const errorHeading = doc.querySelector("main div div h2");
|
||||
let responseText = data.responseText;
|
||||
document.getElementById("reAuthError").textContent = errorHeading.textContent;
|
||||
$('#reAuthError').removeClass('d-none');
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@* <script src="~/lib/jquery/dist/jquery.min.js" defer></script> *@
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"
|
||||
crossorigin="anonymous" defer></script>
|
||||
|
||||
16
src/Views/Shared/_Login.cshtml
Normal file
16
src/Views/Shared/_Login.cshtml
Normal file
@@ -0,0 +1,16 @@
|
||||
@using Microsoft.AspNetCore.Mvc.Localization
|
||||
@inject IViewLocalizer T
|
||||
|
||||
<form method="post" action="/Home/Login" class="mt-4" style="max-width: 400px; margin: auto;">
|
||||
<div class="form-group mb-3">
|
||||
<label for="username" class="form-label">@T["Username"]</label>
|
||||
<input autofocus type="text" class="form-control" id="username" name="username" autocomplete="username" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="password" class="form-label">@T["Password"]</label>
|
||||
<input type="password" class="form-control" id="password" name="password" autocomplete="current-password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary w-100">@T["Login"]</button>
|
||||
</form>
|
||||
Reference in New Issue
Block a user