📋 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
329 lines
10 KiB
Markdown
329 lines
10 KiB
Markdown
# 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`
|
|
```sql
|
|
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`
|
|
```sql
|
|
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`
|
|
```sql
|
|
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
|
|
<?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
|
|
<?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
|
|
1. **Input:** Utente inserisce codice unico
|
|
2. **Validazione:** Controllo formato e checksum
|
|
3. **Ricerca:** Query database per codice
|
|
4. **Verifica:** Controllo stato utente attivo
|
|
5. **Sessione:** Creazione token sessione
|
|
6. **Redirect:** Invio alla dashboard appropriata
|
|
|
|
### LOGOUT PROCESS
|
|
1. **Trigger:** Logout manuale o timeout
|
|
2. **Cleanup:** Rimozione token sessione
|
|
3. **Audit:** Log dell'operazione
|
|
4. **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
|