Initial commit of the Asset Management System, including project structure, Docker configuration, database migrations, and core application files. Added user authentication, asset management features, and basic UI components.
This commit is contained in:
209
app/Controllers/AuthController.php
Normal file
209
app/Controllers/AuthController.php
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Core\BaseController;
|
||||
use App\Models\User;
|
||||
use App\Models\PasswordReset;
|
||||
|
||||
class AuthController extends BaseController
|
||||
{
|
||||
public function showLogin(): string
|
||||
{
|
||||
if ($this->session->isLoggedIn()) {
|
||||
return $this->redirect('/dashboard');
|
||||
}
|
||||
|
||||
return $this->render('auth/login');
|
||||
}
|
||||
|
||||
public function login(): Response
|
||||
{
|
||||
$email = $this->request->post('email');
|
||||
$password = $this->request->post('password');
|
||||
|
||||
// Check if account is locked
|
||||
if ($this->session->isLockedOut()) {
|
||||
$this->flash('error', 'Account ist gesperrt. Bitte warten Sie 15 Minuten.');
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
// Validate input
|
||||
$errors = $this->validate([
|
||||
'email' => 'required|email',
|
||||
'password' => 'required'
|
||||
]);
|
||||
|
||||
if (!empty($errors)) {
|
||||
foreach ($errors as $field => $fieldErrors) {
|
||||
foreach ($fieldErrors as $error) {
|
||||
$this->flash('error', $error);
|
||||
}
|
||||
}
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
// Find user
|
||||
$user = (new User($this->database))->findByEmail($email);
|
||||
|
||||
if (!$user || !$user['active']) {
|
||||
$this->incrementLoginAttempts();
|
||||
$this->flash('error', 'Ungültige Anmeldedaten oder Account inaktiv.');
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
// Verify password
|
||||
if (!password_verify($password, $user['passhash'])) {
|
||||
$this->incrementLoginAttempts();
|
||||
$this->flash('error', 'Ungültige Anmeldedaten.');
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
// Check if password needs rehash
|
||||
if (password_needs_rehash($user['passhash'], PASSWORD_ARGON2ID)) {
|
||||
$newHash = password_hash($password, PASSWORD_ARGON2ID);
|
||||
(new User($this->database))->update($user['id'], ['passhash' => $newHash]);
|
||||
}
|
||||
|
||||
// Reset login attempts
|
||||
$this->session->setLoginAttempts(0);
|
||||
|
||||
// Set user session
|
||||
$this->session->setUser($user);
|
||||
$this->session->setLastActivity();
|
||||
|
||||
// Log audit
|
||||
$this->logAudit('login', 'users', $user['id']);
|
||||
|
||||
$this->flash('success', 'Erfolgreich angemeldet.');
|
||||
return $this->redirect('/dashboard');
|
||||
}
|
||||
|
||||
public function logout(): Response
|
||||
{
|
||||
if ($this->session->isLoggedIn()) {
|
||||
$userId = $this->session->getUserId();
|
||||
$this->logAudit('logout', 'users', $userId);
|
||||
}
|
||||
|
||||
$this->session->logout();
|
||||
$this->flash('success', 'Erfolgreich abgemeldet.');
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
public function showForgotPassword(): string
|
||||
{
|
||||
return $this->render('auth/forgot-password');
|
||||
}
|
||||
|
||||
public function forgotPassword(): Response
|
||||
{
|
||||
$email = $this->request->post('email');
|
||||
|
||||
$errors = $this->validate([
|
||||
'email' => 'required|email'
|
||||
]);
|
||||
|
||||
if (!empty($errors)) {
|
||||
foreach ($errors as $field => $fieldErrors) {
|
||||
foreach ($fieldErrors as $error) {
|
||||
$this->flash('error', $error);
|
||||
}
|
||||
}
|
||||
return $this->redirect('/password/forgot');
|
||||
}
|
||||
|
||||
$user = (new User($this->database))->findByEmail($email);
|
||||
|
||||
if ($user && $user['active']) {
|
||||
$token = bin2hex(random_bytes(32));
|
||||
$expiresAt = date('Y-m-d H:i:s', strtotime('+1 hour'));
|
||||
|
||||
$passwordReset = new PasswordReset($this->database);
|
||||
$passwordReset->create([
|
||||
'user_id' => $user['id'],
|
||||
'token' => $token,
|
||||
'expires_at' => $expiresAt
|
||||
]);
|
||||
|
||||
// Send email (in production, implement email service)
|
||||
// $this->sendPasswordResetEmail($user['email'], $token);
|
||||
}
|
||||
|
||||
// Always show success message for security
|
||||
$this->flash('success', 'Falls die E-Mail-Adresse existiert, wurde ein Reset-Link gesendet.');
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
public function showResetPassword(): string
|
||||
{
|
||||
$token = $this->request->get('token');
|
||||
|
||||
if (!$token) {
|
||||
$this->flash('error', 'Ungültiger Reset-Link.');
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
$passwordReset = new PasswordReset($this->database);
|
||||
$reset = $passwordReset->findByToken($token);
|
||||
|
||||
if (!$reset || strtotime($reset['expires_at']) < time()) {
|
||||
$this->flash('error', 'Reset-Link ist ungültig oder abgelaufen.');
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
return $this->render('auth/reset-password', ['token' => $token]);
|
||||
}
|
||||
|
||||
public function resetPassword(): Response
|
||||
{
|
||||
$token = $this->request->post('token');
|
||||
$password = $this->request->post('password');
|
||||
$passwordConfirm = $this->request->post('password_confirm');
|
||||
|
||||
$errors = $this->validate([
|
||||
'password' => 'required|min:8',
|
||||
'password_confirm' => 'required'
|
||||
]);
|
||||
|
||||
if ($password !== $passwordConfirm) {
|
||||
$this->flash('error', 'Passwörter stimmen nicht überein.');
|
||||
return $this->redirect('/password/reset?token=' . $token);
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
foreach ($errors as $field => $fieldErrors) {
|
||||
foreach ($fieldErrors as $error) {
|
||||
$this->flash('error', $error);
|
||||
}
|
||||
}
|
||||
return $this->redirect('/password/reset?token=' . $token);
|
||||
}
|
||||
|
||||
$passwordReset = new PasswordReset($this->database);
|
||||
$reset = $passwordReset->findByToken($token);
|
||||
|
||||
if (!$reset || strtotime($reset['expires_at']) < time()) {
|
||||
$this->flash('error', 'Reset-Link ist ungültig oder abgelaufen.');
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
// Update user password
|
||||
$userModel = new User($this->database);
|
||||
$userModel->update($reset['user_id'], [
|
||||
'passhash' => password_hash($password, PASSWORD_ARGON2ID)
|
||||
]);
|
||||
|
||||
// Delete used reset token
|
||||
$passwordReset->delete($reset['id']);
|
||||
|
||||
$this->flash('success', 'Passwort erfolgreich geändert. Sie können sich jetzt anmelden.');
|
||||
return $this->redirect('/login');
|
||||
}
|
||||
|
||||
private function incrementLoginAttempts(): void
|
||||
{
|
||||
$attempts = $this->session->getLoginAttempts();
|
||||
$this->session->setLoginAttempts($attempts + 1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user