Gates는 AuthServiceProvider 내부의 boot 메서드에 Gate facade를 사용해 정의한다.
use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
}
// $user가 $post에 접근할 수 있는 조건 설정
------------------------------------------------------
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
Gate::define('update-post', [PostPolicy::class, 'update']);
}
// 이렇게 클래스 콜백 배열을 통해서도 정의가 가능하다
어떠한 action에 대한 인가 처리를 할 때 Gate가 제공하는 allows, denies 메서드를 사용할 수 있다. 두 메서드를 사용할 때 현재 인증한 사용자의 정보를 제공할 필요는 없다.
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
class PostController extends Controller
{
/**
* Update the given post.
*/
public function update(Request $request, Post $post): RedirectResponse
{
if (! Gate::allows('update-post', $post)) {
abort(403);
}
// Update the post...
return redirect('/posts');
}
}
-----------------------------------------------------------
// 만약 현재 인증한 유저가 아닌 다른 유저에 대한 인가를 검증하고 싶다면
// forUser 메서드를 사용해 검증하면 된다
if (Gate::forUser($user)->allows('update-post', $post)) {
// The user can update the post...
}
if (Gate::forUser($user)->denies('update-post', $post)) {
// The user can't update the post...
}
-----------------------------------------------------------
if (Gate::any(['update-post', 'delete-post'], $post)) {
// The user can update or delete the post...
}
if (Gate::none(['update-post', 'delete-post'], $post)) {
// The user can't update or delete the post...
}
// 또한 any, none 메서드를 통해 여러 action들에 대해 동시 검증이 가능하다
인가처리를 하는 동시에 Exception 처리를 진행할 수 있다.
Gate::authorize('update-post', $post);
// The action is authorized...
// 인가에 실패하면 Laravel exception handler가 자동으로 403 에러를 리턴한다
allows, denies, check, any, none, authorize, can, cannot 등의 속성과 블레이드의 @can, @cannot, @canany 속성은 두 번째 파라미터로 배열을 입력받을 수 있다. 해당 배열은 gate closure의 파라미터로 넘겨져 인가 처리에 대한 부가적인 설정을 돕는다.
use App\Models\Category;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
Gate::define('create-post', function (User $user, Category $category, bool $pinned) {
if (! $user->canPublishToGroup($category->group)) {
return false;
} elseif ($pinned && ! $user->canPinPosts()) {
return false;
}
return true;
});
if (Gate::check('create-post', [$category, $pinned])) {
// The user can create the post...
}
단순한 boolean 리턴 타입 외에 다른 방식으로 리턴하고 싶다면 Illuminate\Auth\Access\Response 를 사용할 수 있다.
use App\Models\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::deny('You must be an administrator.');
});
// 삼항 연산자를 통해 에러 메시지를 전달할 수 있다
------------------------------------------------------------
$response = Gate::inspect('edit-settings');
if ($response->allowed()) {
// The action is authorized...
} else {
echo $response->message();
}
// 단순 boolean 타입으로 리턴하는 것이 아니라
// 인가에 대한 전체 응답을 리턴할 수 있다
denyWithStatus 를 통해 HTTP 상태 코드를 커스터마이징 가능하다
use App\Models\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::denyWithStatus(404);
});
----------------------------------------------------------
use App\Models\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::denyAsNotFound();
});
모든 인가 체크 이전에 실행되는 메서드도 생성 가능하다 (like interceptor)
use App\Models\User;
use Illuminate\Support\Facades\Gate;
Gate::before(function (User $user, string $ability) {
if ($user->isAdministrator()) {
return true;
}
});
// 만약 before 속성의 closure 메서드에서 null이 아닌 속성이 리턴된다면 인가 확인의 결과로 사용된다
----------------------------------------------------------
use App\Models\User;
Gate::after(function (User $user, string $ability, bool|null $result, mixed $arguments) {
if ($user->isAdministrator()) {
return true;
}
});
// after 속성도 before 속성과 마찬가지다
인가 처리를 Gate::allowIf, Gate::denyIf 를 통해 Inline 코드로 작성 가능하다
use App\Models\User;
use Illuminate\Support\Facades\Gate;
Gate::allowIf(fn (User $user) => $user->isAdministrator());
Gate::denyIf(fn (User $user) => $user->banned());
// 만약 현재 인증된 유저가 없거나 인가에 실패하면 laravel에서 자동으로 Exception을 발생시킨다