Documentation: https://laravel.com/docs/11.x/authorization#gates
Authorization with a Gate
Let's say we want to prevent authenticated users from accessing invoices for other users. A user should only be allowed to view their invoices but not anyone else's. To achieve this, we can define a Gate:
// inside of the boot method
Gate::define('view-invoice', function (User $user, Invoice $invoice) {
return $user->email === $invoice->customer->Email;
});
Then, in our controller, we can use several different approaches to utilize our Gate:
class InvoiceController extends Controller
{
public function show($id)
{
$invoice = Invoice::with([
'invoiceItems.track',
'invoiceItems.track.album',
'invoiceItems.track.album.artist',
])->find($id);
// Approach 1
if (Gate::denies('view-invoice', $invoice)) {
abort(404);
}
// Approach 2
if (!Gate::allows('view-invoice', $invoice)) {
abort(404);
}
// Approach 3
if (Auth::user()->cannot('view-invoice', $invoice)) {
abort(404);
}
// Approach 4
if (!Auth::user()->can('view-invoice', $invoice)) {
abort(404);
}
return view('invoice.show', [
'invoice' => $invoice,
]);
}
}
We can also access our Gate in a template using the @can
or @cannot
directives:
@can('view-invoice', $invoice)
<a href="{{ route('invoice.show', [ 'id' => $invoice->id ]) }}">
View invoice
</a>
@endcan
@cannot('view-invoice', $invoice)
<p>You don't have access to this invoice.</p>
@endcan
Authorization with a Policy
We can also perform authorization checks via Policies. Policies are classes that organize authorization logic around a particular model.
php artisan make:policy InvoicePolicy --model=Invoice
namespace App\Policies;
use App\Models\Invoice;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class InvoicePolicy
{
public function view(User $user, Invoice $invoice)
{
return $user->email === $invoice->customer->Email;
}
}
class InvoiceController extends Controller
{
public function show($id)
{
$invoice = Invoice::with([
'invoiceItems.track',
'invoiceItems.track.album',
'invoiceItems.track.album.artist',
])->find($id);
// Approach 1
if (Auth::user()->cannot('view', $invoice)) {
abort(404);
}
// Approach 2
if (!Auth::user()->can('view', $invoice)) {
abort(404);
}
return view('invoice.show', [
'invoice' => $invoice,
]);
}
}
Similar to before, we can perform authorization checks in a template via a Policy using the @can
or @cannot
directives:
@can('view', $invoice)
<a href="{{ route('invoice.show', [ 'id' => $invoice->id ]) }}">
View invoice
</a>
@endcan
@cannot('view', $invoice)
<p>You don't have access to this invoice.</p>
@endcan
Documentation: https://laravel.com/docs/11.x/authorization#writing-policies