myCRM/docs/LOGIN.md
2025-11-08 10:26:44 +01:00

7.0 KiB

Login & Authentifizierung

Übersicht

myCRM verwendet Symfony Security mit form-based Login und optionaler "Remember Me" Funktionalität.

Features

Email-basierter Login - Benutzer melden sich mit ihrer Email-Adresse an
Sicheres Password Hashing - Automatisch mit Symfony Password Hasher
Remember Me - "Angemeldet bleiben" für 7 Tage
CSRF Protection - Schutz vor Cross-Site Request Forgery
Automatische Weiterleitung - Nach Login zum Dashboard
Last Login Tracking - Speichert Zeitpunkt des letzten Logins
Inaktive User Blocking - User mit isActive = false können sich nicht einloggen
Vue.js Integration - User-Daten werden an Frontend übergeben

URLs

Route Zweck
/login Login-Seite
/logout Logout (POST)
/ Dashboard (nach Login)

Test-Benutzer

Nach doctrine:fixtures:load verfügbar:

Administrator:
  Email: admin@mycrm.local
  Passwort: admin123
  Rechte: Vollzugriff auf alle Module

Vertriebsmitarbeiter:
  Email: sales@mycrm.local
  Passwort: sales123
  Rechte: Kontakte, Deals, Aktivitäten (ohne Löschrechte)

⚠️ Wichtig: Diese Passwörter nur für Development verwenden!

Security Configuration

# config/packages/security.yaml
security:
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    
    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
    
    firewalls:
        main:
            form_login:
                login_path: app_login
                check_path: app_login
                default_target_path: /
            logout:
                path: app_logout
                target: app_login
            remember_me:
                secret: '%kernel.secret%'
                lifetime: 604800 # 1 week
    
    access_control:
        - { path: ^/login, roles: PUBLIC_ACCESS }
        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
        - { path: ^/, roles: ROLE_USER }

Backend Usage

Controller: Aktuellen User abrufen

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class MyController extends AbstractController
{
    public function index(): Response
    {
        // Get current user
        $user = $this->getUser();
        
        if (!$user) {
            throw $this->createAccessDeniedException();
        }
        
        // User properties
        $email = $user->getEmail();
        $fullName = $user->getFullName();
        $isActive = $user->isActive();
        $lastLogin = $user->getLastLoginAt();
        
        // Check roles
        if ($this->isGranted('ROLE_ADMIN')) {
            // Admin stuff
        }
        
        return $this->render('template.html.twig', [
            'user' => $user
        ]);
    }
}

Service: User von Security Token

use Symfony\Bundle\SecurityBundle\Security;

class MyService
{
    public function __construct(
        private Security $security
    ) {}
    
    public function doSomething(): void
    {
        $user = $this->security->getUser();
        
        if ($user instanceof \App\Entity\User) {
            // Work with user
        }
    }
}

Twig: User-Informationen

{% if app.user %}
    <p>Angemeldet als: {{ app.user.fullName }}</p>
    <p>Email: {{ app.user.email }}</p>
    
    {% if is_granted('ROLE_ADMIN') %}
        <a href="/admin">Admin-Bereich</a>
    {% endif %}
{% else %}
    <a href="{{ path('app_login') }}">Login</a>
{% endif %}

Frontend Usage (Vue.js)

Auth Store (Pinia)

import { useAuthStore } from '@/stores/auth';

// In Component
const authStore = useAuthStore();

// Check authentication
if (authStore.isAuthenticated) {
    console.log('User:', authStore.user);
    console.log('Full Name:', authStore.fullName);
}

// Check roles
if (authStore.hasRole('ROLE_ADMIN')) {
    // Show admin features
}

if (authStore.isAdmin) {
    // Shortcut for ROLE_ADMIN check
}

// Logout
authStore.logout();

In Vue Components

<template>
  <div>
    <p v-if="authStore.isAuthenticated">
      Willkommen, {{ authStore.fullName }}!
    </p>
    
    <button @click="authStore.logout()">
      Abmelden
    </button>
  </div>
</template>

<script setup>
import { useAuthStore } from '@/stores/auth';

const authStore = useAuthStore();
</script>

Event Listeners

LoginSuccessListener

Wird automatisch nach erfolgreichem Login ausgeführt:

// src/EventListener/LoginSuccessListener.php
#[AsEventListener(event: LoginSuccessEvent::class)]
class LoginSuccessListener
{
    public function __invoke(LoginSuccessEvent $event): void
    {
        $user = $event->getUser();
        
        // Update last login timestamp
        $user->setLastLoginAt(new \DateTimeImmutable());
        $this->entityManager->flush();
    }
}

Du kannst weitere Listener hinzufügen für:

  • Audit Logging
  • Login-Benachrichtigungen
  • Session-Tracking
  • etc.

Password Management

Passwort ändern

use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

public function changePassword(
    User $user,
    string $newPassword,
    UserPasswordHasherInterface $passwordHasher
): void {
    $hashedPassword = $passwordHasher->hashPassword($user, $newPassword);
    $user->setPassword($hashedPassword);
    $this->entityManager->flush();
}

Neuen User erstellen

$user = new User();
$user->setEmail('neuer@user.de');
$user->setFirstName('Max');
$user->setLastName('Mustermann');
$user->setIsActive(true);
$user->setRoles(['ROLE_USER']);

$hashedPassword = $passwordHasher->hashPassword($user, 'passwort123');
$user->setPassword($hashedPassword);

$entityManager->persist($user);
$entityManager->flush();

Security Best Practices

  1. Password Hashing - Automatisch mit bcrypt/argon2
  2. CSRF Protection - Aktiviert für Login-Form
  3. Remember Me Cookie - Sicher mit Secret Key
  4. Inactive User Check - User mit isActive = false blockiert
  5. Access Control - Alle Routen außer /login erfordern Authentication
  6. HTTPS Recommended - In Production immer HTTPS verwenden
  7. Session Security - Symfony Session-Handling

Troubleshooting

"Access Denied" nach Login

  • Prüfe User::getRoles() - muss mindestens ['ROLE_USER'] zurückgeben
  • Prüfe access_control in security.yaml

"Bad credentials"

  • Passwort falsch eingegeben
  • User existiert nicht
  • User ist inaktiv (isActive = false)

Remember Me funktioniert nicht

  • Secret Key in .env gesetzt?
  • Cookie wird vom Browser blockiert?
  • Lifetime abgelaufen?

Logout funktioniert nicht

  • Sicherstellen dass /logout als POST Route konfiguriert ist
  • CSRF-Token prüfen

Next Steps

  • Password Reset Funktionalität
  • Two-Factor Authentication (2FA)
  • OAuth Integration (Google, Microsoft)
  • Rate Limiting für Login-Versuche
  • Login History/Audit Log
  • Email-Verifizierung bei Registrierung