Passa al contenuto principale

Claims e policy

Inventario delle lettere autorizzative e dei claim custom in uso in TrainingHub, con il rispettivo significato e i punti di codice che li referenziano.

Cosa fa

TrainingHub usa KSet + un policy provider custom (KSet.Auth.Engines.LettersClaimsPolicyProvider, in D:\repos\dev3sd\Kset) che valuta le policy ASP.NET come richieste di lettere sul claim base associato all'utente. Questa pagina è la mappa unica di:

  • quali lettere (R, C, U, ...) sono effettivamente in uso e cosa significano;
  • quali claim custom esistono al di fuori del pattern auto-generato dal CRUD;
  • quali combinazioni ruolo × claim vengono seedate dal database.

Quando aggiungi una nuova lettera o un claim non-CRUD, aggiorna questa pagina in contestuale al PR.

Modello

I suffissi _X vivono in due posti diversi con ruoli diversi:

DoveEsempioCosa contiene
Codice / config[Authorize(Policy = "page-edu-foo_RU")], <AuthorizeView Policy="page-edu-foo_S">, oss.menu.authPolicy = 'page-edu-foo_M'Le lettere richieste per accedere alla risorsa.
DB — kset.claims.slugpage-edu-fooSolo il nome base. Mai con suffisso _X.
DB — kset.rolesClaims.authorizations'RCUD', 'RS', NULL (= tutte le lettere)Le lettere granted a un ruolo per quel claim.

LettersClaimsPolicyProvider:

  1. Trasforma il claim utente in "{claim.slug}_{rolesClaims.authorizations}" (trim _ finale se authorizations è null).
  2. Estrae la base (parte prima dell'ultimo _) sia dalla policy richiesta che dal claim utente e fa il join su quella.
  3. Se entrambi hanno _, verifica che le lettere richieste siano sottoinsieme di quelle granted.
  4. Se solo uno dei due contiene _, la policy passa (clausola permissiva XOR).

Conseguenza pratica della (4): mettere il suffisso direttamente in claims.slug "funziona" per coincidenza ma rompe il modello. Vedi CLAUDE.md § Convenzioni.

Lettere in uso

LetteraSemanticaOrigineEsempi d'uso
RRead — accesso alla pagina/grid in lettura.CRUD generato + pagine custom.page-job-workers_R (WorkerProfile.razor), page-reg-companies_R (CompanyProfile.razor), page-edu-vw_trainingExpirations_R (menu Scadenze formazione).
CCreate — inserimento di nuovi record.CRUD generato.page-edu-courseSessions_C, page-edu-priorTrainings_C (quick action su WorkerProfile).
UUpdate — modifica record esistente.CRUD generato.page-job-workers_U (quick action "Modifica anagrafica").
DDelete — cancellazione record.CRUD generato.Tutti i CRUD generati.
MMenu — visibilità voce nel menu laterale.Convention oss.menu.authPolicy.page-edu-teachers_M, page-edu-trainingTopics_M, page-iso-certifications_M, ecc. (definite in TrainingHub.Database/Scripts/PostDeploy/02-menu.sql).
SSend / azione custom — gating di un'azione non-CRUD specifica della pagina.Uso manuale.page-teacher-letters_S (firma lettera in LetterDetail.razor), page-teacher-attendance_S (upload PDF registro in Attendance.razor), page-edu-sessionPlanner_S (avvio wizard Nuova sessione).

Note di interpretazione.

  • R/C/U/D sono prodotte automaticamente dal CRUD generator: ogni pagina CRUD generata espone tutte e quattro le lettere per la propria entità.
  • M è il gating del link nel menu, non della pagina: separare _M da _R consente di mostrare/nascondere la voce indipendentemente dall'accesso alla pagina (es. dare R ad un ruolo ma tenere il link fuori dal menu finché non ottiene anche M).
  • S è semantica: il policy provider non sa che "S = send". È convenzione applicativa: tutte le azioni non-CRUD passano per _S. Se serve discriminare più azioni custom sulla stessa entità, vedi Anti-pattern sotto.

Nessuna altra lettera è in uso al 2026-05-11. Le lettere sono case-sensitive nel confronto del policy provider, quindi mantenere maiuscole anche nelle nuove introduzioni.

Claim CRUD con uso non-standard delle lettere

Alcune entità CRUD reali usano le lettere in modo più granulare rispetto al semplice "pagina completa". Documentarle qui evita ambiguità nella gestione dei grant.

Slug (in kset.claims)Entità DB_R_C_DNote
page-edu-sessionDocumentsedu.sessionDocumentsVista step Documenti + bottoni GeneraUpload file (AddPolicy del DocumentsEmbedGrid)Elimina fileClaim auto-generata da Oster; admin riceve CRUDM via pattern page-edu-% in sync-rolesClaims-admin-teacher.sql — nessun grant manuale necessario.

Claim custom (non auto-generate da CRUD)

Le claim auto-generate seguono page-<schema>-<table> dove <schema> corrisponde a uno schema del DB (edu, job, reg, inv, iso, ...). Le claim qui sotto non corrispondono a un'entità CRUD: hanno schema o slug "virtuale" e vanno mantenute manualmente.

Slug (in kset.claims)Schema "virtuale"Cosa gatingPunti d'uso
page-dashboard-compliancedashboardCruscotto conformità aziende (no CRUD sotto).Components/Pages/ComplianceDashboard/CompanyProspect.razor, CompaniesTrainingOverview.razor (_R).
page-import-training-coursesimportWizard import corsi pregressi da Excel.Components/Pages/Import/TrainingCoursesImport.razor (_R).
page-teacher-dashboardteacherArea docente — home.Components/Pages/TeacherArea/Dashboard.razor (_R).
page-teacher-calendarteacherArea docente — calendario impegni.Components/Pages/TeacherArea/Calendar.razor (_R).
page-teacher-lettersteacherArea docente — lettere d'incarico (lettura + firma).Letters.razor, LetterDetail.razor (_R, _S per firma).
page-teacher-attendanceteacherArea docente — registro presenze (lettura + chiusura + upload).Attendance.razor (_R, _U chiusura, _S upload PDF).
page-edu-sessionPlanneredu (virtuale)Avvio wizard "Nuova sessione" dal menu top-level.Voce menu new_session (definita in PostDeploy/02-menu.sql, _S).
page-appointments-calendarappointmentsCalendario globale appuntamenti formativi (non è CRUD diretto).Voce menu appointments_calendar (definita in PostDeploy/02-menu.sql, _R).

Le kset.claims sono auto-generate da Oster (non seedate a mano). I grant per ruolo (kset.rolesClaims) di admin e teacher vivono nello script TrainingHub.Database/Scripts/sync-rolesClaims-admin-teacher.sql, registrato su Oster come maintenance script idempotente. Le voci di menu (con il loro authPolicy) sono dichiarate in TrainingHub.Database/Scripts/PostDeploy/02-menu.sql.

Ruoli seedati e loro grant

RuoloClaimauthorizations grantedSorgente seed
teacherpage-teacher-dashboardRScripts/sync-rolesClaims-admin-teacher.sql
teacherpage-teacher-calendarRidem
teacherpage-teacher-lettersRSidem (R lettura, S firma)
teacherpage-teacher-attendanceRUSidem (R lettura, U chiusura registro, S upload PDF)

I grant dei ruoli admin e teacher sono dichiarativi e autoritativi: vivono nello script sync-rolesClaims-admin-teacher.sql (registrato su Oster come maintenance script idempotente, ordinato dopo lo script Oster che genera le kset.claims). admin = pattern page-{schema}-* con eccezioni in testa allo script; teacher = lista curata. Niente grant manuali via UI per questi due ruoli.

Anti-pattern noti

1. Suffisso _X nello slug di kset.claims

-- ❌ SBAGLIATO
INSERT INTO [kset].[claims] ([slug]) VALUES (N'page-teacher-letters_S');

-- ✅ CORRETTO
INSERT INTO [kset].[claims] ([slug]) VALUES (N'page-teacher-letters');
INSERT INTO [kset].[rolesClaims] ([roleId], [claimId], [authorizations])
VALUES (@teacherRoleId, @claimId, N'RS');

Errore "trascinato" su più sessioni. Lo slug in kset.claims deve restare senza suffisso; le lettere vanno solo in kset.rolesClaims.authorizations.

2. Suffisso semantico multi-parola (_S_StartWizard, _S_RemoveAndQueue)

Presenti in:

  • Components/CRUD/edu/TrainingRequest.razor:74page-edu-trainingRequests_S_StartWizard
  • Components/CRUD/edu/WorkerTrainingDetail.razor:277page-edu-workerTrainingDetails_S_RemoveAndQueue

Il policy provider prende le lettere dopo l'ultimo _: in questi casi diventa StartWizard / RemoveAndQueue, lettere maiuscole e minuscole che non sono lettere autorizzative reali. Funziona oggi solo per via della clausola XOR permissiva (utenti con claim senza _ passano comunque). Da rifattorizzare: una sola azione _S per entità è gestibile; per due azioni distinte servono o due claim differenti (page-edu-trainingRequests-startWizard come claim a sé) o due lettere differenti (ma siamo limitati al pool ASCII maiuscole).

3. Una claim per ogni lettera (anziché una claim base + lettere granted)

-- ❌ SBAGLIATO — esplode il numero di righe in claims
('page-edu-foo_R'), ('page-edu-foo_C'), ('page-edu-foo_U'), ('page-edu-foo_D')

-- ✅ CORRETTO — una sola claim, lettere in rolesClaims.authorizations
('page-edu-foo')

Come aggiungere un nuovo claim custom

  1. Decidi se è davvero non-CRUD (un'entità CRUD generata espone già R/C/U/D automaticamente).
  2. Le kset.claims sono auto-generate da Oster: non seedarle a mano. Se serve un claim "virtuale" non legato a un'entità (es. page-teacher-*, page-import-*), verifica come venga prodotto da Oster.
  3. Concedi le lettere ai ruoli admin/teacher aggiungendo la riga in TrainingHub.Database/Scripts/sync-rolesClaims-admin-teacher.sql (poi ri-registralo su Oster come maintenance script isMaintenance=1, preSync=0, ordinato dopo lo script Oster di generazione claim). Per gli altri ruoli: UI Role Claims Assignment.
  4. Se il claim gating una voce di menu, dichiarala in TrainingHub.Database/Scripts/PostDeploy/02-menu.sql con il relativo authPolicy (suffisso _M/_R/_S).
  5. Usa la policy in codice con il suffisso corretto: [Authorize(Policy = "page-...-foo_R")], AuthorizeView, oss.menu.authPolicy.
  6. Aggiorna la sezione Claim custom di questa pagina.

Come aggiungere una nuova lettera

  1. Verifica che la semantica non sia già coperta da R/C/U/D/S/M. In particolare: _S è il catch-all per qualsiasi azione non-CRUD; introdurre una nuova lettera ha senso solo se serve discriminare più azioni custom sulla stessa entità per ruoli diversi.
  2. Sceglie una lettera maiuscola non in uso (lookup nella tabella Lettere in uso sopra).
  3. Documenta la nuova lettera prima di iniziare ad usarla.
  4. Concedi la lettera ai ruoli interessati via UI Role Claims Assignment o via seed.

Riferimenti codice

  • D:\repos\dev3sd\Kset\KSet.Auth\Engines\LettersClaimsPolicyProvider.cs — logica di match policy → claim utente.
  • D:\repos\dev3sd\Kset\KSet.Auth\Engines\ClaimsTransformationBase.cs — costruzione del claim utente da kset.claims + kset.rolesClaims.
  • TrainingHub.Database/Scripts/sync-rolesClaims-admin-teacher.sql — grant dichiarativi kset.rolesClaims per admin/teacher (maintenance script Oster idempotente).
  • TrainingHub.Database/Scripts/PostDeploy/02-menu.sql — definizione dichiarativa del menu (con oss.menu.authPolicy, suffissi _M/_R/_S); rigenerabile con PostDeploy/_gen/gen-menu.ps1.
  • CLAUDE.md § Convenzioni — promemoria sul modello policy vs claim.