Login Passwort reset
* Passwort Reset Funktion implementiert
This commit is contained in:
41
Layout/default/UserPasswordReset/forgot-password-sent.php
Normal file
41
Layout/default/UserPasswordReset/forgot-password-sent.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title><?= MFAPPNAME_FULL ?> | Link versendet</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>fontawesome/css/all.min.css">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>css/adminlte.css">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>css/fonts.css?<?= date('U') ?>">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>css/main.css?<?= date('U') ?>">
|
||||
<style>
|
||||
.alert-success {
|
||||
color: #155724;
|
||||
background-color: #d4edda;
|
||||
border-color: #c3e6cb;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="hold-transition login-page">
|
||||
<div class="login-box">
|
||||
<div class="login-logo">
|
||||
<a href="<?= self::getUrl("/") ?>"><img
|
||||
src="<?= self::getResourcePath() ?>assets/images/<?= MFAPPNAME_SLUG ?>-logo.png"/></a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body login-card-body">
|
||||
<p class="login-box-msg">Anfrage erhalten</p>
|
||||
<div class="alert alert-success text-center" role="alert">
|
||||
Wenn ein Konto mit diesem Benutzernamen oder dieser E-Mail existiert, wurde ein Link zum Zurücksetzen des Passworts gesendet.
|
||||
</div>
|
||||
<p class="mt-3 mb-1 text-center">
|
||||
<a href="<?= self::getUrl("mfLogin", "index") ?>">Zurück zum Login</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
48
Layout/default/UserPasswordReset/forgot-password.php
Normal file
48
Layout/default/UserPasswordReset/forgot-password.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title><?= MFAPPNAME_FULL ?> | Passwort vergessen</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>fontawesome/css/all.min.css">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>css/adminlte.css">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>css/fonts.css?<?= date('U') ?>">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>css/main.css?<?= date('U') ?>">
|
||||
</head>
|
||||
<body class="hold-transition login-page">
|
||||
<div class="login-box">
|
||||
<div class="login-logo">
|
||||
<a href="<?= self::getUrl("/") ?>"><img
|
||||
src="<?= self::getResourcePath() ?>assets/images/<?= MFAPPNAME_SLUG ?>-logo.png"/></a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body login-card-body">
|
||||
<p class="login-box-msg">Passwort vergessen</p>
|
||||
<p class="text-muted text-center mb-3">Gib deinen Benutzernamen oder Email ein, um einen Link zum Zurücksetzen des Passworts zu erhalten.</p>
|
||||
|
||||
<form action="<?= self::getUrl("UserPasswordReset", "sendResetLink") ?>" method="post">
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" name="Username" class="form-control" placeholder="Benutzer" required>
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">
|
||||
<span class="fas fa-envelope"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-primary btn-block">Link anfordern</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="mt-3 mb-1">
|
||||
<a href="<?= self::getUrl("mfLogin", "index") ?>">Zurück zum Login</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
57
Layout/default/UserPasswordReset/reset-password.php
Normal file
57
Layout/default/UserPasswordReset/reset-password.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title><?= MFAPPNAME_FULL ?> | Passwort zurücksetzen</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>fontawesome/css/all.min.css">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>css/adminlte.css">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>css/fonts.css?<?= date('U') ?>">
|
||||
<link rel="stylesheet" href="<?= self::getResourcePath() ?>css/main.css?<?= date('U') ?>">
|
||||
</head>
|
||||
<body class="hold-transition login-page">
|
||||
<div class="login-box">
|
||||
<div class="login-logo">
|
||||
<a href="<?= self::getUrl("/") ?>"><img
|
||||
src="<?= self::getResourcePath() ?>assets/images/<?= MFAPPNAME_SLUG ?>-logo.png"/></a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body login-card-body">
|
||||
<p class="login-box-msg">Neues Passwort festlegen</p>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger"><?= $error ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="<?= self::getUrl("UserPasswordReset", "updatePassword") ?>" method="post">
|
||||
<input type="hidden" name="token" value="<?= $token ?>" />
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<input type="password" name="Password" class="form-control" placeholder="Neues Passwort" required>
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">
|
||||
<span class="fas fa-lock"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group mb-3">
|
||||
<input type="password" name="Password_confirm" class="form-control" placeholder="Passwort bestätigen" required>
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">
|
||||
<span class="fas fa-lock"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-primary btn-block">Passwort speichern</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -19,7 +19,7 @@ if ($requesttype == "2fa" || $requesttype == "false2fa") {
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="mb-0 col-5">
|
||||
<input type="number" required min="0" max="99999" class="form-control"
|
||||
<input autofocus type="number" required min="0" max="99999" class="form-control"
|
||||
name="TwofactorCode" id="TwofactorCode"/>
|
||||
</div>
|
||||
|
||||
@@ -87,6 +87,7 @@ if ($requesttype == "2fa" || $requesttype == "false2fa") {
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.noselect {
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
-webkit-user-select: none; /* Safari */
|
||||
@@ -134,6 +135,9 @@ if ($requesttype == "2fa" || $requesttype == "false2fa") {
|
||||
<?= $error ?>
|
||||
<div class="row">
|
||||
<div class="col-6 col-lg-8">
|
||||
<p class="mb-1 mt-1">
|
||||
<a href="<?= self::getUrl("UserPasswordReset", "forgotPassword") ?>">Passwort vergessen?</a>
|
||||
</p>
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col-6 col-lg-4">
|
||||
@@ -166,6 +170,13 @@ if ($requesttype == "2fa" || $requesttype == "false2fa") {
|
||||
$('#TwofactorCode').remove();
|
||||
$('form').submit();
|
||||
});
|
||||
$(document).ready(function () {
|
||||
if ($('#TwofactorCode').length > 0) {
|
||||
$('#TwofactorCode').focus();
|
||||
} else {
|
||||
$('#mfUsername').focus();
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
108
application/UserPasswordReset/UserPasswordResetController.php
Normal file
108
application/UserPasswordReset/UserPasswordResetController.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
class UserPasswordResetController extends mfBaseController
|
||||
{
|
||||
protected function indexAction()
|
||||
{
|
||||
self::redirect("UserPasswordReset", "forgotPassword");
|
||||
}
|
||||
|
||||
protected function forgotPasswordAction()
|
||||
{
|
||||
$this->layout()->setTemplate("UserPasswordReset/forgot-password");
|
||||
}
|
||||
|
||||
protected function sendResetLinkAction($request)
|
||||
{
|
||||
$username = $this->db()->escape($request['Username']);
|
||||
$res = $this->db()->select(MFUSERTABLE, "*", "username='$username' OR email='$username'");
|
||||
|
||||
if ($this->db()->num_rows($res)) {
|
||||
$user = $this->db()->fetch_object($res);
|
||||
$token = bin2hex(random_bytes(32));
|
||||
$expires = time() + 3600;
|
||||
|
||||
$this->db()->update(MFUSERTABLE, array(
|
||||
'password_reset_token' => $token,
|
||||
'password_reset_expires' => $expires
|
||||
), "id=" . (int)$user->id);
|
||||
|
||||
$resetLink = "https://".MFAPPNAME.".xinon.at/UserPasswordReset/resetPassword?token=" . $token;
|
||||
|
||||
$email = new Emailnotification();
|
||||
$email->setTo($user->email);
|
||||
$email->setFrom('noreply@xinon.at','XINON No-Reply');
|
||||
$email->setSubject("Passwort zurücksetzen für " . MFAPPNAME_FULL);
|
||||
|
||||
$textBody = "Hallo " . $user->username . ",\n\n" .
|
||||
"Klicke auf den folgenden Link, um dein Passwort zurückzusetzen. Der Link ist eine Stunde gültig.\n\n" .
|
||||
$resetLink . "\n\n" .
|
||||
"Wenn du diese Anfrage nicht gestellt hast, ignoriere diese E-Mail.\n";
|
||||
|
||||
$htmlBody = "<h2>Passwort zurücksetzen</h2>" .
|
||||
"<p>Hallo " . $user->username . ",</p>" .
|
||||
"<p>Klicke auf den folgenden Link, um dein Passwort zurückzusetzen. Der Link ist eine Stunde gültig.</p>" .
|
||||
'<p><a href="' . $resetLink . '">Passwort jetzt zurücksetzen</a></p>' .
|
||||
"<p>Wenn du diese Anfrage nicht gestellt hast, ignoriere diese E-Mail bitte.</p>";
|
||||
|
||||
$email->setBody($textBody);
|
||||
$email->setHtmlBody($htmlBody);
|
||||
$email->send();
|
||||
}
|
||||
$this->layout()->setTemplate("UserPasswordReset/forgot-password-sent");
|
||||
}
|
||||
|
||||
protected function resetPasswordAction($request)
|
||||
{
|
||||
if (empty($request['token'])) {
|
||||
self::redirect("mfLogin", "index");
|
||||
return;
|
||||
}
|
||||
|
||||
$token = $this->db()->escape($request['token']);
|
||||
$res = $this->db()->select(MFUSERTABLE, "*", "password_reset_token='$token' AND password_reset_expires > " . time());
|
||||
|
||||
if (!$this->db()->num_rows($res)) {
|
||||
$this->layout()->setTemplate("mfLogin/Index");
|
||||
return;
|
||||
}
|
||||
|
||||
$this->layout()->set("token", $token);
|
||||
$this->layout()->setTemplate("UserPasswordReset/reset-password");
|
||||
}
|
||||
|
||||
protected function updatePasswordAction($request)
|
||||
{
|
||||
$token = $this->db()->escape($request['token']);
|
||||
$password = $request['Password'];
|
||||
$password_confirm = $request['Password_confirm'];
|
||||
|
||||
if (empty($token) || empty($password) || $password !== $password_confirm) {
|
||||
$error="Passwörter stimmen nicht überein oder die Anfrage ist ungültig.";
|
||||
$this->layout()->set("error",$error,);
|
||||
|
||||
$this->layout()->set("token", $token);
|
||||
$this->layout()->setTemplate("UserPasswordReset/reset-password");
|
||||
return;
|
||||
}
|
||||
|
||||
$res = $this->db()->select(MFUSERTABLE, "*", "password_reset_token='$token' AND password_reset_expires > " . time());
|
||||
|
||||
if (!$this->db()->num_rows($res)) {
|
||||
$this->layout()->setTemplate("mfLogin/Index");
|
||||
return;
|
||||
}
|
||||
|
||||
$user = $this->db()->fetch_object($res);
|
||||
$new_hash = mfLoginController::generatePasswordHash($password);
|
||||
|
||||
$this->db()->update(MFUSERTABLE, array(
|
||||
'password' => $new_hash,
|
||||
'password_reset_token' => NULL,
|
||||
'password_reset_expires' => NULL
|
||||
), "id=" . (int)$user->id);
|
||||
|
||||
$this->layout()->setFlash("Dein Passwort wurde erfolgreich geändert. Du kannst dich jetzt einloggen.", "success");
|
||||
self::redirect("mfLogin", "index");
|
||||
}
|
||||
}
|
||||
33
db/migrations/20250805145608_worker_add_password_reset.php
Normal file
33
db/migrations/20250805145608_worker_add_password_reset.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class WorkerAddPasswordReset extends AbstractMigration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if($this->getEnvironment() == "thetool") {
|
||||
$table = $this->table("Worker");
|
||||
$table->addColumn("password_reset_token", "string", ["null" => true, "after" => "twofactorrequired"]);
|
||||
$table->addColumn("password_reset_expires", "integer", ["null" => true, "default" => null, "after" => "password_reset_token"]);
|
||||
$table->update();
|
||||
}
|
||||
|
||||
if($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if($this->getEnvironment() == "thetool") {
|
||||
$this->table("Worker")->removeColumn("password_reset_token")->save();
|
||||
$this->table("Worker")->removeColumn("password_reset_expires")->save();
|
||||
}
|
||||
|
||||
if($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user