Rollen, permissies, context en autorisatie
2.1 Doel
OefenHub gebruikt vanaf Feature 11-5 een permission-based RBAC-model. Rollen blijven bestaan, maar een rol is niet langer het directe autorisatiebewijs voor routes, schermen, menu-items, frontpageblokken of domeinacties.
Dit hoofdstuk beschrijft daarom het onderscheid tussen:
- gebruikersaccount;
- roltoekenning;
- permissions;
- rol-permissiekoppelingen;
- samengestelde frontpage- en navigatiecontext;
- relatiecontext;
- niveau-, leerling-, kind-, oefening- of beheercontext;
- zichtbare navigatie;
- feitelijke server-side autorisatie.
De kernregel is:
Een gebruiker mag een functie alleen gebruiken wanneer de gebruiker de vereiste permission heeft én de actuele server-side domein-/objectcontext geldig is.
Clientstate, routeparameters, zichtbare knoppen, oude browserselecties, bookmarks, filters en lokale UI-state mogen nooit autorisatie afdwingen of verruimen.
2.2 Account, rol, permissie en context
OefenHub onderscheidt vijf lagen.
| Laag | Betekenis |
|---|---|
| Account | Het interne Users-record dat de OefenHub-gebruiker representeert en via ExternalId gekoppeld is aan de identity provider. |
| Roltoekenning | Een actieve koppeling tussen gebruiker en rol via UserRoles. |
| Permission | Een expliciete technische toestemming met code volgens <resource>.<action>[.<scope>], bijvoorbeeld student-results.read.assigned. |
| Rol-permissiekoppeling | Een actieve koppeling tussen rol en permission via RolePermissions. |
| Domein-/objectcontext | De server-side geldige context voor het concrete object, zoals eigen run, toegewezen leerling, gekoppeld kind, niveau-eigenaarschap of supportflow. |
Een gebruiker met een actieve rol heeft dus alleen de permissions die via actieve rollen gekoppeld zijn. Zelfs met een permission is objecttoegang niet automatisch onbeperkt.
Voorbeelden:
- een gebruiker met
student-results.read.assignedmag alleen resultaten lezen van leerlingen die binnen de actuele docentcontext vallen; - een gebruiker met
student-results.read.childrenmag alleen resultaten lezen van actief gekoppelde kinderen; - een gebruiker met
frontpage.view.teacherziet het docentfrontpageblok, maar krijgt daardoor nog geen leerlingresultaten; - een gebruiker met
administrator-accounts.read.allmag accountinformatie lezen binnen beheercontext, maar geen identity-providercredentials zien; - een gebruiker met
practice-run.answer.ownmag alleen antwoorden in de eigen actieve oefenrun.
2.3 Rollen als bundels
Rollen blijven functioneel relevant, maar niet als directe autorisatiecheck.
| Rol | Functie in RBAC | Belangrijke grens |
|---|---|---|
| Leerling | Bundel voor eigen oefenen, eigen resultaten, eigen geschiedenis, gedeelde oefeningen en leerlingnavigatie. | Kan niet gecombineerd worden met Ouder/voogd, Docent, Beheerder, TestDocent of toekomstige Admin-rol. |
| Ouder/voogd | Bundel voor ouder-/voogdfrontpage, kinderen, kindresultaten en live meekijken met actief gekoppelde kinderen. | Kan geen oefening namens een kind starten, hervatten, beantwoorden, afronden, corrigeren, opnieuw maken of delen. |
| Docent | Bundel voor docentfrontpage, onderwijsstructuur, leerlingen, niveauautorisaties, resultaten binnen toegewezen context en live meekijken binnen docentcontext. | Ziet leerlingresultaten alleen binnen eigen docent-, niveau- en leerlingcontext. |
| Beheerder | Bundel voor applicatiebeheer, accountbeheer, contentbeheer, modules, categorieën, meldingen en supportflows. | Beheert niet automatisch rollen, permissies of rol-permissiekoppelingen; dat wordt in Feature 17 story 091 apart uitgewerkt. |
| TestDocent | Bundel voor gecontroleerde testmodulecontexten. | Niet-publieke rol; alleen relevant waar module- en testcontext dit expliciet toestaan. |
| Admin / autorisatiebeheerder | Toekomstige separate bundel voor rollen- en permissiebeheer. | Buiten scope van Feature 11-5; exacte naam/code en beheerinterface worden uitgewerkt in story 17-091. |
2.4 Niet-combineerbare leerlingrol
De rol Leerling is functioneel niet combineerbaar met Ouder/voogd, Docent, Beheerder, TestDocent of toekomstige Admin-/autorisatiebeheerrollen.
De reden is dat de leerlingfrontend wezenlijk anders werkt dan de overige contexten:
- leerlingen oefenen zelf;
- leerlingen hebben een actieve niveaucontext;
- leerlingen kunnen tijdens een oefenrun niet worden afgeleid door gewone applicatiesignalen;
- leerlingnavigatie is categorie- en oefengericht;
- leerlingvoortgang, resultaten en geschiedenis zijn persoonlijk;
- leerlingacties mogen niet vermengd worden met beheer-, docent-, ouder- of autorisatiebeheeracties.
Wanneer een natuurlijke persoon ook docent, ouder/voogd, beheerder of autorisatiebeheerder moet zijn, hoort dat niet via hetzelfde account met leerlingrol te gebeuren.
2.5 Combineerbare rollen en samengestelde UI
De rollen Ouder/voogd, Docent en Beheerder mogen gecombineerd voorkomen binnen één account.
Bij combinatierollen geldt:
- de effectieve permissions zijn de distinct union van alle actieve permissions uit alle actieve rollen;
- de frontpage wordt runtime samengesteld uit permissiongedreven blokken;
- menu-items en profielmenu-items worden zichtbaar op basis van permissions, niet op basis van rolchecks;
- navigatie-items worden niet dubbel getoond;
- de volgorde van frontpageblokken volgt een vaste UI-prioriteit;
- docentinzage geeft geen ouder-/voogdinzage;
- ouder-/voogdinzage geeft geen docentinzage;
- beheercontext verruimt geen gewone eindgebruikerscontext tenzij een expliciete beheer- of supportflow actief is.
De vaste UI-prioriteit voor gecombineerde frontpages is:
- Beheerder;
- Docent;
- Ouder/voogd;
- Leerling.
Omdat de leerlingrol niet combineerbaar is, verschijnt het leerlingblok alleen op een leerlingfrontpage. De prioriteit blijft wel vastgelegd voor fallback- en validatielogica.
Bij Docent + Ouder/voogd wordt één samengestelde frontpage getoond met docentblokken vóór ouder-/voogdblokken. Bij combinaties met Beheerder worden eerst de beheerderblokken getoond, daarna docentblokken en daarna ouder-/voogdblokken.
2.6 Publieke en niet-publieke rollen
Rollen kennen functioneel een onderscheid tussen publieke en niet-publieke rollen.
| Type | Betekenis |
|---|---|
| Publieke rol | Mag binnen de toegestane registratie- of profielcontext door een gebruiker zelf gekozen of geactiveerd worden. |
| Niet-publieke rol | Mag uitsluitend via expliciete beheer-/adminflow worden toegekend of ingetrokken. |
Niet-publieke rollen zijn minimaal:
- Beheerder;
- TestDocent;
- toekomstige Admin-/autorisatiebeheerrol.
Een gebruiker mag niet via zelfregistratie, profielwijziging, clientstate, routeparameter, relatie-uitnodiging of oude sessiecontext een niet-publieke rol activeren.
Toekennen of intrekken van rollen moet altijd permissioncache-invalidatie veroorzaken voor de betrokken gebruiker. Beheer van rollen, permissions en rol-permissionkoppelingen zelf blijft buiten scope van Feature 11-5 en wordt voorbereid in Feature 17 story 091.
2.7 Permissions
Permissions zijn expliciete technische rechten die aan rollen worden gekoppeld via RolePermissions.
Naamgevingsconventie:
<resource>.<action>[.<scope>]
Voorbeelden:
| Permission | Betekenis |
|---|---|
frontpage.view.teacher | Docentfrontpageblok mag zichtbaar zijn. |
menu.view.guardian-children | Kinderenmenu voor ouder/voogd mag zichtbaar zijn. |
student-results.read.own | Eigen leerlingresultaten lezen. |
student-results.read.assigned | Resultaten van toegewezen leerlingen lezen. |
student-results.read.children | Resultaten van actief gekoppelde kinderen lezen. |
teacher-levels.update.collaborating | Een niveau bewerken als collaborator. |
administrator-system-settings.update.all | Systeeminstellingen beheren binnen beheercontext. |
Het volledige permissionregister staat in RBAC-permissieregister.
2.8 Permissioncheck versus domeincheck
Een permission opent een ingang, maar vervangt geen domein-/objectcontrole.
| Stap | Vraag | Voorbeeld |
|---|---|---|
| Permissioncheck | Heeft de gebruiker de vereiste permission? | student-results.read.assigned |
| Domeincheck | Valt het concrete object binnen de toegestane context? | Is deze leerling toegewezen aan deze docent en valt de run binnen een geautoriseerd niveau? |
Voorbeelden:
student-results.read.assignedvereist daarna een docent-leerlingrelatie en niveauautorisatie;student-results.read.childrenvereist daarna een actieve GuardianStudent-relatie;teacher-levels.update.collaboratingvereist daarna een actieve collaboratorstatus op het niveau;practice-run.resume.ownvereist daarna dat de run van de huidige leerling is en niet afgerond is;administrator-teacher-support.update.allvereist daarna een expliciete supportflow en auditregistratie.
Domeinchecks blijven lokaal bij het domein dat de brondata bezit. Er komt geen centrale autorisatie-monoliet met alle leerling-, kind-, niveau-, ticket-, berichten- en runregels.
2.9 Relatiecontext
Relaties tussen accounts zijn zelfstandige autorisatiebouwstenen.
Een actieve relatie kan onder meer nodig zijn voor:
- vriendschappen tussen leerlingen;
- gedeelde oefeningen;
- ouder-/voogdinzage;
- ouder-/voogd-live-meekijken;
- docent-leerlingtoegang;
- docentresultaten binnen de eigen context;
- docent-docentsamenwerking;
- beheerder-beheerdercommunicatie.
Relaties worden vastgelegd per relatietype en context. Daardoor kan dezelfde natuurlijke persoon via verschillende niet-leerlingrollen verschillende relaties hebben met dezelfde leerling.
Voorbeelden:
- iemand kan als Ouder/voogd een ouderrelatie met een leerling hebben;
- dezelfde persoon kan als Docent ook een docent-leerlingrelatie met die leerling hebben;
- deze twee relaties blijven functioneel gescheiden;
- acties op de ene relatie mogen de andere relatie niet impliciet wijzigen.
2.10 Docentcontext
Docentfunctionaliteit werkt vanuit permissions en server-side docentcontext.
Een docent kan verschillende soorten toegang hebben:
| Context | Betekenis |
|---|---|
| Eigenaar van niveau | Mag het niveau beheren en eigenaarschap onder voorwaarden overdragen. |
| Collaborator op niveau | Mag binnen dat niveau onderwijsinhoud bewerken, maar krijgt geen leerling-, resultaat- of live-meekijktoegang door collaboration alleen. |
| Docent-leerlingrelatie | Maakt leerlinggerichte docentflows mogelijk, maar geeft niet automatisch toegang tot ieder niveau. |
| Niveauautorisatie voor leerling | Bepaalt voor welke niveaus een leerling binnen docentcontext toegang heeft en waarover de docent resultaatinzage heeft. |
| Docent zonder geldige objectcontext | Krijgt geen resultaat-, leerling- of live-inzage buiten de toegestane docentcontext. |
Een docent ziet resultaten alleen wanneer zowel de permission als de eigen docentcontext geldig zijn. Directe URL’s, gemanipuleerde filters, oude bookmarks of gewijzigde autorisaties mogen geen resultaatdata buiten die context tonen.
2.11 Ouder-/voogdcontext
Ouder-/voogdfunctionaliteit gebruikt permissions plus de actieve GuardianStudent-relatie als domeincontrole.
Een ouder/voogd mag voor actief gekoppelde kinderen:
- kinderenoverzicht raadplegen;
- kindinformatie bekijken;
- resultaten en geschiedenis over alle historische niveaus raadplegen;
- resultaatdetails openen;
- PDF-export starten;
- online-status bekijken;
- live meekijken wanneer een actieve oefenrun beschikbaar is.
Een ouder/voogd mag niet:
- een oefening namens het kind starten;
- een oefening hervatten;
- antwoorden geven;
- voortgang corrigeren;
- resultaten wijzigen;
- een oefening opnieuw maken namens het kind;
- een oefening delen namens het kind.
Na ontkoppeling vervalt reguliere ouder-/voogdinzage direct voor nieuwe raadpleeg-, detail-, export- en liveacties. Historische runs blijven bestaan, maar worden niet gedeeltelijk getoond aan een gebruiker zonder actieve relatie.
2.12 Beheercontext en toekomstige Admin-context
Een beheerder heeft brede applicatiebeheermogelijkheden, maar beheercontext is geen vrije bypass op alle eindgebruikersfunctionaliteit.
Beheeracties zijn alleen toegestaan binnen expliciete beheer- of supportflows en vereisen passende beheerpermissions, zoals administrator-accounts.read.all, administrator-system-settings.update.all of tickets.resolve.all.
Een beheerder mag onder meer:
- accounts beheren binnen de ondersteunde accountbeheerregels;
- content beheren;
- categorieën beheren en migreren;
- modules beheren en migreren;
- docentondersteuning uitvoeren;
- meldingen behandelen;
- beheerlogging en geschiedenis raadplegen.
Een beheerder mag niet automatisch:
- rollen, permissions of rol-permissionkoppelingen beheren;
- live meekijken in actieve leerlingruns;
- reguliere leerlingoefeningen namens leerlingen uitvoeren;
- ouder-/voogd- of docentcontext stilzwijgend overnemen buiten supportflows;
- identity-providercredentials aanpassen;
- wachtwoorden wijzigen;
- autorisaties alleen via clientstate afdwingen.
Rollen- en permissionbeheer wordt apart voorbereid voor een toekomstige Admin-/autorisatiebeheerrol in Feature 17 story 091.
2.13 Accountstatus
Users.IsActive = false blokkeert reguliere OefenHub-toegang.
Dit betekent:
- er wordt geen gewone frontpage opgebouwd;
- permissioncache mag niet als toegangsbewijs worden gebruikt voor inactieve accounts;
- bestaande historie wordt niet verwijderd;
- relaties, berichten, meldingen, runs en auditdata blijven waar nodig historisch herleidbaar;
- heractiveren vereist een expliciete beheerhandeling;
- na heractiveren worden permissions, rollen, contexten en autorisaties opnieuw server-side bepaald.
Een gedeactiveerd of geanonimiseerd account mag niet via oude sessies, browsercontext, directe API-aanroepen of realtimeverbindingen alsnog beveiligde OefenHub-data raadplegen.
2.14 Permissioncache
Permissionchecks mogen niet bij iedere controle een databasequery veroorzaken.
Regels:
- Bij login probeert OefenHub de effectieve permissions van de gebruiker te laden en 60 minuten te cachen, tenzij appsettings anders configureren.
- De checkmethode kijkt altijd eerst in
IMemoryCache. - Bij cache hit gebruikt de check de gecachete permission-set.
- Bij cache miss haalt de check alle actieve permissions uit alle actieve rollen opnieuw op en zet deze opnieuw in de cache.
- De cache is per gebruiker en bevat distinct permission-codes.
- De cacheduur komt uit appsettings, bijvoorbeeld
Authorization:PermissionCacheDurationMinutes. IMemoryCacheis voorlopig voldoende omdat er geen geplande multi-instance deployment is.- Bij toekomstige horizontale schaal moet dit worden vervangen of aangevuld met
IDistributedCacheof een gedeelde invalidatiestrategie.
Cache-invalidatie is verplicht bij:
- publieke rolkeuze;
- publieke rolwijziging via profiel;
- toekennen of intrekken van een gebruikersrol;
- deactiveren/heractiveren/anonimiseren van een account;
- latere rol-permissionwijzigingen;
- latere permissiondeactivatie;
- expliciete beheer-/systemactie om de authcache van een gebruiker te legen.
2.15 Autorisatieprincipes
Voor alle rollen, permissions en contexten gelden de volgende autorisatieprincipes.
- Autorisatie wordt server-side bepaald.
- Iedere raadpleeg-, detail-, export-, mutatie- en liveactie herhaalt de relevante controle.
- Een zichtbaar menu-item is geen autorisatiebewijs.
- Een zichtbare knop is geen autorisatiebewijs.
- Routeparameters zijn geen autorisatiebewijs.
- Filters, paginering en zoektermen zijn geen autorisatiebron.
- Browsergeschiedenis, bookmarks en oude selectiecontexten mogen toegang niet verruimen.
- Clientstate mag presentatie versnellen, maar nooit rechten toekennen.
- Bij ontbrekende toegang wordt geen gedeeltelijke gevoelige inhoud getoond.
- Autorisatiefouten mogen geen kindnaam, runinhoud, antwoorddata, tokens, technische payloads of interne foutdetails lekken.
- Lege toestanden zijn geen autorisatiefouten wanneer de gebruiker wel toegang heeft maar er geen data beschikbaar is.
2.16 Lege toestanden versus autorisatiefouten
Het FO maakt expliciet onderscheid tussen lege toestanden en autorisatiefouten.
| Situatie | Betekenis |
|---|---|
| Geen gekoppelde kinderen | Geldige lege ouder-/voogdtoestand. |
| Geen afgeronde resultaten | Geldige lege resultaten- of geschiedenisweergave. |
| Geen online kinderen of leerlingen | Geldige lege onlineweergave. |
| Geen actieve oefeningen binnen categorie | Geldige lege of verborgen oefenaanbodtoestand volgens zichtbaarheidregels. |
| Geen permission voor de ingang | Autorisatiefout of veilige toegang-geweigerdafhandeling. |
| Geen toegang tot kind, leerling, run, niveau of beheerobject | Autorisatiefout of veilige toegang-geweigerdafhandeling. |
| Oude URL naar niet langer toegankelijke run | Autorisatiefout; geen gedeeltelijke resultaatdata tonen. |
Een lege toestand mag de gebruiker informeren. Een autorisatiefout moet veilig blokkeren.
2.17 Frontend, routes, guards en permission metadata
Frontendroutes, menu’s en knoppen mogen de gebruiker helpen navigeren, maar de backend blijft leidend.
OefenHub gebruikt declaratieve permission metadata, bijvoorbeeld:
- endpointmetadata zoals
RequirePermission("student-results.read.assigned"); - componentmetadata zoals
RequiresPermission("frontpage.view.teacher"); - Blazor helpers zoals
PermissionViewofOefenHubPermissionGuard; - servicechecks via
IOefenHubPermissionService.
ASP.NET RequireAuthorization() blijft bruikbaar voor baseline authenticatie. ASP.NET policies zijn optioneel implementatiedetail en niet de primaire functionele bron van OefenHub-autorisatie.
Routeguards mogen:
- vroegtijdig navigatie blokkeren;
- de gebruiker naar een veilige context sturen;
- zichtbare menu-items verbergen;
- fout- of toegangsschermen tonen.
Routeguards mogen niet:
- server-side autorisatie vervangen;
- oude clientstate vertrouwen;
- routeparameters als bewijs gebruiken;
- domeinregels overslaan;
- gegevens tonen voordat server-side toegang is vastgesteld.
2.18 Audit en securitylogging
Niet iedere permissioncheck hoeft een zichtbare melding of auditregel op te leveren. Wel moeten relevante beheeracties, rolmutaties, permission-/rolepermission-mutaties, lifecyclewijzigingen, supportacties en gevoelige geweigerde toegangspogingen herleidbaar kunnen zijn.
Voorbeelden van auditwaardige acties:
- niet-publieke rol toekennen of intrekken;
- permission of rol-permissionkoppeling wijzigen;
- permissioncache expliciet invalidaten door systeem of beheer;
- account uitschakelen of heractiveren;
- account anonimiseren;
- docentondersteuning uitvoeren;
- collaborator forceren;
- eigenaarschap overdragen;
- categorie- of modulemigratie uitvoeren;
- beheerdermelding heropenen;
- live-meekijksessie starten;
- ouder-/voogdrelatie beëindigen.
Securitylogging bij geweigerde toegang mag geen gevoelige inhoud opslaan, zoals antwoorden, runpayloads, tokens of persoonsgegevens waarvoor de gebruiker geen toegang heeft.
2.19 Gerelateerde bronverwijzingen
| Bron | Link |
|---|---|
| Ontwerpbron — RBAC-permissieregister | RBAC-permissieregister |
| Ontwerpbron — autorisatiematrix | Autorisatiematrix |
| Technisch Ontwerp — identiteit en rolcontext | Identiteit, authenticatie en rolcontext |
| Technisch Ontwerp — autorisatie | Autorisatie, policies en server-side contextcontrole |
| Technisch Ontwerp — rolflows | Rollenflows technisch |
| Database-informatie — identiteit en autorisatie | Identiteit en autorisatie |
| Database-informatie — relatiebeheer | Relatiebeheer |
| Database-informatie — docentstructuur en leerlingtoegang | Docentstructuur en leerlingtoegang |
| FO — account, profiel en voorkeuren | Account, profiel en voorkeuren |
| FO — relatiebeheer | Relatiebeheer |
| FO — live meekijken | Live meekijken |