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 weupdate-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.
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.
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 inboot() 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.
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.
Expliciet overschrijven in de applicatie
Roep jepolicy() 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 globaleGate::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, dieReportsServiceProvider::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?
Geraadpleegde primaire bronnen
- Officiële Laravel-documentatie: Autorisatie
- Officiële Laravel-documentatie: Packageontwikkeling
- Framework v13.42.0: registratie, resolutie en forUser van de Gate
- Framework v13.42.0: AuthServiceProvider, die de Gate als singleton registreert
- Framework v13.42.0: boot en booted van Application
- Framework v13.42.0: officiële tests van de autorisatie-Gate