📋 Commit iniziale con: - ✅ Documentazione unificata in docs/ - ✅ Codice Laravel in netgescon-laravel/ - ✅ Script automazione in scripts/ - ✅ Configurazione sync rsync - ✅ Struttura organizzata e pulita 🔄 Versione: 2025.07.19-1644 🎯 Sistema pronto per Git distribuito
10 KiB
10 KiB
SPECIFICHE AUTENTICAZIONE - NetGesCon Unified Platform
🎯 OBIETTIVO
Implementare un sistema di autenticazione unificato tramite codice utente unico che sostituisce il sistema tradizionale username/password, con gestione centralizzata delle sessioni e accesso alle cartelle dati specifiche per utente/ruolo.
🔑 SISTEMA AUTENTICAZIONE CODICE UNICO
STRUTTURA CODICE UTENTE
Formato: [PREFISSO]-[IDENTIFICATIVO]-[CHECKSUM]
Esempio: ADM-001234-A7B
CON-098765-K3Z
FOR-543210-M9P
PREFISSI RUOLO
- SUP - Super Admin
- ADM - Amministratore
- CON - Condomino
- FOR - Fornitore
- COL - Collaboratore
GENERAZIONE CODICI
- Algoritmo: Base su hash di dati utente + timestamp
- Checksum: 3 caratteri alfanumerici per validazione
- Unicità: Controllo globale su tutti i ruoli
- Regenerazione: Possibile in caso di compromissione
📂 STRUTTURA CARTELLE DATI
CARTELLA PRINCIPALE
/data/users/
├── SUP-000001-X9Z/ # Super Admin
│ ├── config/ # Configurazioni globali
│ ├── logs/ # Log sistema
│ ├── backups/ # Backup automatici
│ └── reports/ # Report globali
├── ADM-001234-A7B/ # Amministratore Rossi
│ ├── condominii/ # Dati condominii gestiti
│ │ ├── stabile_001/
│ │ ├── stabile_002/
│ │ └── ...
│ ├── documenti/ # Documenti personali
│ ├── templates/ # Template personalizzati
│ └── reports/ # Report specifici
├── CON-098765-K3Z/ # Condomino Bianchi
│ ├── documenti/ # Documenti ricevuti
│ ├── comunicazioni/ # Comunicazioni con admin
│ ├── estratti_conto/ # Estratti conto personali
│ └── pagamenti/ # Storico pagamenti
└── FOR-543210-M9P/ # Fornitore VerdiSrl
├── preventivi/ # Preventivi inviati
├── fatture/ # Fatture emesse
├── ordini/ # Ordini ricevuti
└── comunicazioni/ # Comunicazioni
PERMESSI CARTELLE
- Lettura/Scrittura: Solo proprietario cartella
- Backup Admin: Super admin accesso sola lettura
- Condivisione: Tramite sistema interno (no accesso diretto)
- Audit: Log di tutti gli accessi
🔐 IMPLEMENTAZIONE TECNICA
DATABASE SCHEMA
Tabella users
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_code VARCHAR(20) UNIQUE NOT NULL, -- Codice utente unico
email VARCHAR(255) UNIQUE, -- Email opzionale
phone VARCHAR(20), -- Telefono opzionale
role_id BIGINT NOT NULL, -- FK a roles
status ENUM('active', 'suspended', 'disabled') DEFAULT 'active',
data_folder VARCHAR(255) NOT NULL, -- Percorso cartella dati
last_login TIMESTAMP NULL,
login_attempts INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_code (user_code),
INDEX idx_role_id (role_id),
INDEX idx_status (status)
);
Tabella user_sessions
CREATE TABLE user_sessions (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
session_token VARCHAR(255) NOT NULL,
ip_address VARCHAR(45),
user_agent TEXT,
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_session_token (session_token),
INDEX idx_expires_at (expires_at),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
Tabella login_logs
CREATE TABLE login_logs (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_code VARCHAR(20),
ip_address VARCHAR(45),
user_agent TEXT,
login_success BOOLEAN NOT NULL,
failure_reason VARCHAR(255) NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_code (user_code),
INDEX idx_login_success (login_success),
INDEX idx_created_at (created_at)
);
MIDDLEWARE AUTHENTICATION
CodeAuthMiddleware.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use App\Services\AuthService;
class CodeAuthMiddleware
{
protected $authService;
public function __construct(AuthService $authService)
{
$this->authService = $authService;
}
public function handle(Request $request, Closure $next)
{
// Verifica presenza codice utente nella sessione
$userCode = $request->session()->get('user_code');
if (!$userCode) {
return redirect()->route('login');
}
// Valida sessione attiva
if (!$this->authService->validateSession($userCode)) {
$request->session()->flush();
return redirect()->route('login')->with('error', 'Sessione scaduta');
}
// Carica dati utente nel request
$user = $this->authService->getUserByCode($userCode);
$request->merge(['auth_user' => $user]);
return $next($request);
}
}
SERVICE LAYER
AuthService.php
<?php
namespace App\Services;
use App\Models\User;
use App\Models\UserSession;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
class AuthService
{
public function authenticateByCode(string $userCode, string $ipAddress, string $userAgent): ?User
{
// Valida formato codice
if (!$this->validateCodeFormat($userCode)) {
$this->logFailedLogin($userCode, $ipAddress, $userAgent, 'Invalid code format');
return null;
}
// Cerca utente
$user = User::where('user_code', $userCode)
->where('status', 'active')
->first();
if (!$user) {
$this->logFailedLogin($userCode, $ipAddress, $userAgent, 'User not found');
return null;
}
// Crea sessione
$sessionToken = $this->createSession($user, $ipAddress, $userAgent);
// Log login riuscito
$this->logSuccessfulLogin($userCode, $ipAddress, $userAgent);
return $user;
}
public function generateUserCode(string $rolePrefix, array $userData): string
{
// Genera ID progressivo
$lastUser = User::where('user_code', 'LIKE', $rolePrefix . '-%')
->orderBy('user_code', 'desc')
->first();
$nextId = 1;
if ($lastUser) {
$parts = explode('-', $lastUser->user_code);
$nextId = intval($parts[1]) + 1;
}
$identifier = sprintf('%06d', $nextId);
// Genera checksum
$checksum = $this->generateChecksum($rolePrefix, $identifier, $userData);
return $rolePrefix . '-' . $identifier . '-' . $checksum;
}
private function generateChecksum(string $prefix, string $identifier, array $userData): string
{
$data = $prefix . $identifier . json_encode($userData) . config('app.key');
$hash = hash('sha256', $data);
// Prendi i primi 3 caratteri e convertili in alfanumerico
$checksum = '';
for ($i = 0; $i < 6; $i += 2) {
$hex = substr($hash, $i, 2);
$dec = hexdec($hex);
$checksum .= base_convert($dec, 10, 36);
}
return strtoupper(substr($checksum, 0, 3));
}
private function validateCodeFormat(string $code): bool
{
// Formato: XXX-NNNNNN-XXX
$pattern = '/^[A-Z]{3}-\d{6}-[A-Z0-9]{3}$/';
return preg_match($pattern, $code);
}
public function createDataFolder(User $user): bool
{
$basePath = config('filesystems.disks.user_data.root', storage_path('app/user_data'));
$userPath = $basePath . '/' . $user->user_code;
if (!file_exists($userPath)) {
return mkdir($userPath, 0755, true) && $this->createUserSubfolders($userPath, $user->role->name);
}
return true;
}
private function createUserSubfolders(string $userPath, string $roleName): bool
{
$subfolders = match($roleName) {
'super-admin' => ['config', 'logs', 'backups', 'reports'],
'admin' => ['condominii', 'documenti', 'templates', 'reports'],
'condomino' => ['documenti', 'comunicazioni', 'estratti_conto', 'pagamenti'],
'fornitore' => ['preventivi', 'fatture', 'ordini', 'comunicazioni'],
'collaboratore' => ['documenti', 'task', 'comunicazioni'],
default => ['documenti', 'comunicazioni']
};
foreach ($subfolders as $folder) {
$path = $userPath . '/' . $folder;
if (!mkdir($path, 0755, true)) {
return false;
}
}
return true;
}
}
🔄 FLUSSO AUTENTICAZIONE
LOGIN PROCESS
- Input: Utente inserisce codice unico
- Validazione: Controllo formato e checksum
- Ricerca: Query database per codice
- Verifica: Controllo stato utente attivo
- Sessione: Creazione token sessione
- Redirect: Invio alla dashboard appropriata
LOGOUT PROCESS
- Trigger: Logout manuale o timeout
- Cleanup: Rimozione token sessione
- Audit: Log dell'operazione
- Redirect: Invio alla pagina login
SESSION MANAGEMENT
- Durata: 8 ore lavorative (configurabile)
- Refresh: Automatico su attività
- Concurrent: Massimo 3 sessioni attive per utente
- Cleanup: Job automatico rimozione sessioni scadute
🛡️ SICUREZZA
PROTEZIONI
- Rate Limiting: Max 5 tentativi login/minuto per IP
- Account Lockout: Dopo 5 tentativi falliti (15 min block)
- Session Hijacking: Controllo IP e User-Agent
- CSRF Protection: Token su tutte le form
AUDIT E MONITORING
- Login Logs: Tutti i tentativi di accesso
- Access Logs: Accesso a file/cartelle utente
- Error Logs: Tentativi non autorizzati
- Performance: Tempi di risposta autenticazione
Ultima modifica: $(Get-Date -Format "dd/MM/yyyy HH:mm")
Versione: 1.0
Stato: Da Implementare