Naar hoofdinhoud gaan
Soms wil je autorisatie toevoegen aan de modellen die een package levert, terwijl de gebruikende applicatie de ruimte houdt om die te vervangen door eigen regels. Als je de koppeling tussen model en policy expliciet vastlegt en de gebruiker pas beoordeelt op het moment dat de autorisatie wordt uitgevoerd, scheid je de registratie van de beslissingen per request. Deze pagina verwijst naar de standaardbranch 13.x van de officiële Laravel-documentatie en naar de officiële implementatie en tests van de nieuwste Framework-release v13.42.0, gecontroleerd op 10 november 2026. Zie de autorisatiegids voor de basis van autorisatie en package auto-discovery voor het laden van providers.

Niet afhankelijk zijn van de User-klasse van de applicatie

Als voorbeeld voegen we update-autorisatie toe aan Acme\Reports\Models\Report uit het package. We gaan ervan uit dat de tabel acme_reports een kolom owner_id heeft waarin de authenticatie-identifier van de eigenaar staat. Hoe je migraties levert, lees je in packagemigraties. src/Models/Report.php is een gewoon Eloquent-model.
Als de policy van het package App\Models\User als type opgeeft, wordt die afhankelijk van de namespace en modelstructuur van de gebruikende applicatie. Heb je alleen de authenticatie-identifier van de gebruiker nodig, gebruik dan het Laravel-contract Authenticatable. Zet het volgende in src/Policies/ReportPolicy.php.
Eerst worden null-identifiers uitgesloten. Het typeverschil tussen een integer uit de database en een string wordt opgevangen door beide als string te vergelijken. In dit voorbeeld mag alleen de eigenaar bijwerken. In applicaties met meerdere gebruikerstypen of guards controleer je ook of de identifier alleen het subject uniek identificeert. Zo niet, vervang de policy dan door een eigen policy die de grenzen van gebruikerstype of tenant meeneemt.
Authenticatable is een contract voor onder meer de authenticatie-identifier. Het biedt geen isAdministrator() of methoden om rollen op te halen. Heb je packagespecifieke rechteninformatie nodig, definieer dan een apart contract en laat de gebruikende applicatie een implementatie injecteren.

De koppeling registreren in een serviceprovider

Registreer in boot() van src/ReportsServiceProvider.php alleen de modellen die het package bezit.
Gate::policy() slaat de klassenaam van de policy op met de klassenaam van het model als sleutel. De registratie zelf maakt geen policy aan, voert geen databasequery uit en beoordeelt geen gebruiker. Pas wanneer de policy nodig is, bijvoorbeeld via Gate::getPolicyFor(), wordt die met make() van de container aangemaakt. Daardoor kun je afhankelijkheden in de constructor van de policy injecteren. De plaats van Report en ReportPolicy past ook bij de standaard auto-discovery, maar hier wordt expliciet geregistreerd om duidelijk te maken welke koppeling het package levert. Registratie alleen past geen autorisatie toe op HTTP-endpoints. Roep vóór het bijwerken bijvoorbeeld in een controller het volgende aan.
Bij weigering wordt een AuthorizationException gegooid, die bij normale HTTP-afhandeling een 403-response oplevert. De argumenten van de policymethode verschillen tussen update, dat een model ontvangt, en abilities zoals create, die de klassenaam van het model ontvangen. Volg de aanroepwijze uit de autorisatiegids.

De resolutievolgorde van policies lezen

Gate::getPolicyFor() zet een object om naar zijn klassenaam en zoekt in de volgende volgorde. Dit is de volgorde waarin een policy wordt gekozen, niet de uitvoeringsvolgorde van alle autorisatiehooks. Zolang er dus een expliciete registratie voor dezelfde klasse Report bestaat, wordt de policy niet vervangen als je alleen #[UsePolicy] of de naamgeving aanpast. Gebruikt de applicatie daarentegen een model dat Report uitbreidt, dan gaat een policy die via het eigen attribuut van de kindklasse of via afleiding wordt gevonden vóór de expliciete registratie op de ouder. Controleer het ook met de modelklasse die je daadwerkelijk gebruikt.
guessPolicyNamesUsing() voegt geen callback toe aan een lijst, maar vervangt de ene afleidingscallback van de Gate. Als een onafhankelijk package die alleen voor zijn eigen modellen instelt, beïnvloedt dat ook de afleiding van de applicatie en van andere packages. Gebruik als basis policy()-registraties voor de modellen die het package bezit.

Expliciet overschrijven in de applicatie

Roep je policy() opnieuw aan voor hetzelfde model, dan vervangt de latere registratie de koppeling. Het simpelweg in de boot() van een andere provider zetten hangt af van de laadvolgorde. Een mogelijkheid is om vanuit AppServiceProvider::boot() van de applicatie een callback te registreren voor wanneer de applicatie klaar is met opstarten.
ApplicationReportPolicy is een policy die de applicatie implementeert. Registreert het package in een normale boot(), dan draait deze callback daarna. Het is geen mechanisme dat onvoorwaardelijk voorrang krijgt, ook niet boven herregistraties in andere booted-callbacks of later geladen providers. De registrerende provider van het package is in dit voorbeeld geen deferred provider. Als alternatief kun je de koppeling ongewijzigd laten en in de container vervangen waarnaar ReportPolicy::class wordt opgelost. resolvePolicy() vraagt de container elke keer om de policy op te lossen, maar of je echt een nieuwe instantie krijgt, hangt af van de binding van die policy. Vermijd ontwerpen die gebruikers- of requestinformatie in de constructor ophalen en in een singleton-policy bewaren.

Hooks die alle autorisatie raken gescheiden houden

Bij een normale Gate-controle draait eerst de globale Gate::before(). Geeft die iets anders dan null terug, dan wordt de beoordeling door de policy niet uitgevoerd. Het diagram toont alleen het pad waarin een policy wordt gevonden en de bijbehorende methode kan worden aangeroepen. De globale after-hooks daarna en de terugval op Gate-definities wanneer de policy de doelmethode niet heeft, zijn weggelaten. Registreer geen globale Gate::before() die alle abilities toestaat, alleen om beheerdersafhandeling binnen je package te implementeren. Daarmee sta je ook de autorisatie van andere packages en van de applicatie toe. Een before() binnen de policy geldt alleen voor die policy, maar wordt niet aangeroepen als de methode voor de ability ontbreekt. Wil je de volgende methode laten beslissen, geef dan null terug in plaats van false. Daarnaast vereist update() in dit voorbeeld een niet-nullable Authenticatable, waardoor de policymethode voor gasten niet wordt uitgevoerd. Zonder overschrijving van het resultaat door bijvoorbeeld globale hooks wordt de request geweigerd. Wil je gasten toestaan, bijvoorbeeld voor openbaar bekijken, voorzie dan apart in een nullable gebruikersargument en een expliciete controle.

Registratie en beoordeling apart testen

We gaan uit van de Testbench-basisklasse uit packagetests, die ReportsServiceProvider::class laadt in getPackageProviders(). Hieronder staat een voorbeeld van tests/Feature/ReportPolicyTest.php. Voor gebruikers wordt het generieke authenticatiemodel van Laravel gebruikt, zodat je zonder op te slaan in de database kunt beoordelen.
forUser() herschrijft de gebruiker van de gedeelde Gate niet. Het maakt een aparte Gate aan en geeft daarbij de koppelingen, abilities en callbacks van dat moment mee. Een al aangemaakte Gate per gebruiker ziet daarom latere wijzigingen in policyregistraties op de gedeelde Gate niet. Rond registraties af tijdens het opstarten en bewaar Gates per gebruiker niet in langlevende services. In de applicatie heb je ook controles met de echte guard en het echte gebruikersmodel nodig, plus HTTP-tests voor het update-endpoint. Alleen met de tests hierboven verifieer je niet dat autorisatie op de route is toegepast of in welk formaat de eigenaar-identifier in de database wordt opgeslagen.

Contracten om te behouden bij updates

  • Zijn de resultaten voor eigenaar, niet-eigenaren, gasten en records zonder eigenaar ongewijzigd?
  • Komen de gepubliceerde ability-namen overeen met de argumenten van de policymethoden?
  • Werkt het vervangen van de policy door de applicatie nog steeds?
  • Als je kindmodellen ondersteunt: is de policy die daadwerkelijk voor de kindklasse wordt gekozen correct?
  • Worden echte updaterequests, inclusief de globale hooks van de applicatie, toegestaan en geweigerd zoals verwacht?
Updates die bestaande abilities verwijderen of het standaard toestaan of weigeren veranderen, beïnvloeden het gedrag van applicaties. Behandel autorisatiewijzigingen samen met versiecompatibiliteitsbeheer als publiek contract.

Geraadpleegde primaire bronnen

Laatst gewijzigd op 10 november 2026