modulo 18 di 24 / Ore 41-60
Moduli 17-24 / Checkpoint 60 ore
Autorizzazioni minime: chi può fare cosa
Come applicare il principio del minimo privilegio nel Registro del laboratorio scolastico: ruoli, operazioni consentite e come limitarle anche senza autenticazione reale.
Autorizzazioni minime: chi può fare cosa
Questa lezione appartiene al Modulo 18 — Sicurezza minima e validazione.
Il lavoro continua il progetto guida, il Registro del laboratorio scolastico, aggiungendo un livello di controllo sulle operazioni sensibili senza introdurre un sistema di autenticazione completo.
Obiettivo della lezione
Definisci chi può fare cosa nel Registro e implementa un controllo semplice che blocca le operazioni non consentite per un dato ruolo. Nessun sistema di login reale — ma regole esplicite nel codice.
Alla fine devi avere: una funzione puoEseguire(ruolo, operazione) usata nei casi d’uso prima di procedere, e una documentazione dei ruoli.
Il principio del minimo privilegio
Il principio del minimo privilegio dice: ogni parte del sistema deve avere accesso solo a ciò che è strettamente necessario per fare il suo lavoro. Nel Registro scolastico, significa che non tutti possono fare tutto.
Senza autenticazione reale, puoi comunque modellare i ruoli e farli rispettare nella logica applicativa. L’utente che usa il browser non è autenticato, ma il sistema può sapere in che “modalità” sta operando — impostata manualmente o tramite un semplice parametro.
Ruoli nel Registro del laboratorio
Per il Registro del laboratorio scolastico, tre ruoli sono sufficienti:
"studente"— può cercare strumenti e visualizzare i propri prestiti. Non può registrare strumenti né segnalare guasti."tecnico"— può aprire e chiudere prestiti, segnalare guasti. Non può registrare nuovi strumenti."responsabile"— può fare tutto: registrare strumenti, gestire prestiti, approvare segnalazioni.
Le operazioni principali del Registro sono:
"registra-strumento"— aggiunge uno strumento al catalogo"apri-prestito"— avvia un prestito"chiudi-prestito"— termina un prestito"segnala-guasto"— cambia lo stato di uno strumento a guasto"cerca-strumenti"— legge il catalogo (disponibile a tutti)
Procedura guidata
- Crea
src/application/autorizzazioni.jscon la mappa dei permessi per ruolo. - Scrivi la funzione
puoEseguire(ruolo, operazione)che consulta la mappa. - Aggiungi un controllo all’inizio di ogni caso d’uso sensibile.
- Aggiungi un campo
ruoloal contesto dell’applicazione o passalo come parametro. - Verifica manualmente: chiama un caso d’uso con ruolo
"studente"per un’operazione vietata e controlla che venga bloccata.
Attività in classe
Compila la mappa dei permessi prima di scrivere il codice:
## Mappa dei permessi
Operazione: registra-strumento
Ruoli autorizzati:
Operazione: apri-prestito
Ruoli autorizzati:
Operazione: chiudi-prestito
Ruoli autorizzati:
Operazione: segnala-guasto
Ruoli autorizzati:
Operazione: cerca-strumenti
Ruoli autorizzati:
Poi confronta la tua mappa con quella del compagno e discuti le differenze.
Spiegazione guidata per studiare
Il controllo delle autorizzazioni vive nel livello Application, non nel dominio e non nella Presentation. Metterlo nella Presentation significa poterlo aggirare facilmente (basta nascondere un pulsante, non bloccare l’operazione). Metterlo nel dominio significa mescolare regole di business con politiche di accesso — che sono cose diverse.
Il livello Application è il posto giusto: coordina le operazioni, conosce il contesto (chi sta agendo), e può bloccare prima di delegare al dominio.
Un sistema senza login può comunque avere ruoli. Il ruolo corrente può essere impostato all’avvio dell’applicazione tramite una variabile di configurazione, un parametro URL, o una selezione manuale iniziale. Non è sicuro come un sistema di autenticazione reale, ma è sufficiente per modellare il comportamento corretto e ragionarci sopra.
Passo per passo nel progetto
- Crea
src/application/autorizzazioni.js:
// application/autorizzazioni.js
const PERMESSI = {
"studente": ["cerca-strumenti"],
"tecnico": ["cerca-strumenti", "apri-prestito", "chiudi-prestito", "segnala-guasto"],
"responsabile": ["cerca-strumenti", "registra-strumento", "apri-prestito", "chiudi-prestito", "segnala-guasto"]
};
export function puoEseguire(ruolo, operazione) {
const permessiRuolo = PERMESSI[ruolo];
if (!permessiRuolo) return false;
return permessiRuolo.includes(operazione);
}
- Usa
puoEseguirenel caso d’usoregistraStrumento:
// application/registraStrumento.js
import { puoEseguire } from "./autorizzazioni.js";
export function registraStrumento({ nome, categoria, ruolo }, archivio) {
if (!puoEseguire(ruolo, "registra-strumento")) {
throw new Error("OPERAZIONE_NON_AUTORIZZATA");
}
if (!nome || nome.trim() === "") {
throw new Error("NOME_OBBLIGATORIO");
}
const strumenti = archivio.caricaTutti();
const nuovoStrumento = {
id: crypto.randomUUID(),
nome: nome.trim(),
categoria,
stato: "disponibile"
};
strumenti.push(nuovoStrumento);
archivio.salva(strumenti);
return nuovoStrumento;
}
- Usa
puoEseguirenel caso d’usoapriPrestito:
// application/apriPrestito.js
import { puoEseguire } from "./autorizzazioni.js";
export function apriPrestito({ strumentoId, ruolo }, archivioStrumenti, archivioPrestiti) {
if (!puoEseguire(ruolo, "apri-prestito")) {
throw new Error("OPERAZIONE_NON_AUTORIZZATA");
}
const strumenti = archivioStrumenti.caricaTutti();
const strumento = strumenti.find(s => s.id === strumentoId);
if (!strumento) throw new Error("STRUMENTO_NON_TROVATO");
if (strumento.stato !== "disponibile") throw new Error("STRUMENTO_NON_DISPONIBILE");
strumento.stato = "in-prestito";
archivioStrumenti.salva(strumenti);
const prestiti = archivioPrestiti.caricaTutti();
const nuovoPrestito = {
id: crypto.randomUUID(),
strumentoId,
dataApertura: new Date().toISOString().split("T")[0],
dataChiusura: null
};
prestiti.push(nuovoPrestito);
archivioPrestiti.salva(prestiti);
return nuovoPrestito;
}
- In
main.js, passa il ruolo corrente ai casi d’uso:
// main.js
const RUOLO_CORRENTE = "tecnico"; // cambia per testare diversi ruoli
btnPresta.addEventListener("click", () => {
try {
const prestito = apriPrestito(
{ strumentoId: inputId.value, ruolo: RUOLO_CORRENTE },
archivioStrumenti,
archivioPrestiti
);
mostraMessaggio(`Prestito aperto: ${prestito.id}`);
} catch (errore) {
if (errore.message === "OPERAZIONE_NON_AUTORIZZATA") {
mostraMessaggio("Non hai i permessi per questa operazione.");
} else {
mostraMessaggio("Errore: " + errore.message);
}
}
});
Esempio JS — verifica manuale in console
import { puoEseguire } from "./src/application/autorizzazioni.js";
console.log(puoEseguire("studente", "apri-prestito")); // false
console.log(puoEseguire("tecnico", "apri-prestito")); // true
console.log(puoEseguire("responsabile", "registra-strumento")); // true
console.log(puoEseguire("studente", "cerca-strumenti")); // true
console.log(puoEseguire("ruolo-inesistente", "apri-prestito")); // false
Prova di comprensione
Rispondi per iscritto:
- Perché il controllo del ruolo non sta nella Presentation (nel gestore del click)?
- Cosa cambia se aggiungiamo un quarto ruolo
"osservatore"che può solo cercare? - Perché l’errore si chiama
"OPERAZIONE_NON_AUTORIZZATA"e non"Accesso negato"? - Come modificheresti
puoEseguireper loggare ogni tentativo non autorizzato?
Errori da evitare
- nascondere i pulsanti nell’UI come unico controllo — è una misura di comodità, non di sicurezza;
- mettere la logica dei permessi direttamente nei gestori degli eventi;
- usare condizioni
if (ruolo === "responsabile")sparse in tutto il codice invece di centralizzare inautorizzazioni.js; - lanciare eccezioni con messaggi tecnici che arrivano all’utente — converti sempre l’errore in un messaggio leggibile nella Presentation.
Prodotto da consegnare
Il file src/application/autorizzazioni.js con la mappa dei permessi e puoEseguire, più almeno due casi d’uso che la usano. Come verifica: chiama un caso d’uso con un ruolo non autorizzato e mostra che viene bloccato con un messaggio chiaro.
Checklist di chiusura
puoEseguireè inapplication/, non indomain/né inpresentation/;- almeno due casi d’uso usano il controllo di autorizzazione;
- la Presentation converte
"OPERAZIONE_NON_AUTORIZZATA"in un messaggio leggibile; - la mappa dei permessi è centralizzata e non duplicata;
- ho testato manualmente almeno un caso di operazione vietata.
Risultato atteso
Ho creato autorizzazioni.js con la mappa dei permessi per tre ruoli.
I casi d'uso registraStrumento e apriPrestito controllano il ruolo prima di procedere.
Ho verificato che uno studente non può aprire un prestito.
Il prossimo passo: aggiungere un quarto ruolo "osservatore" per le consultazioni pubbliche.