Laravel Authorization - Gates

정종일·2023년 9월 26일
0

Laravel

목록 보기
4/9
💡 Laravel에서는 여러가지 빌트인 authentication 서비스를 지원한다. gates와 polices를 활용해 인가 처리가 가능하다

💡 Gates

Writing Gates

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']);
}

// 이렇게 클래스 콜백 배열을 통해서도 정의가 가능하다

Authorizing Actions

어떠한 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들에 대해 동시 검증이 가능하다

Authorizing Or Throwing Exceptions

인가처리를 하는 동시에 Exception 처리를 진행할 수 있다.

Gate::authorize('update-post', $post);
 
// The action is authorized...

// 인가에 실패하면 Laravel exception handler가 자동으로 403 에러를 리턴한다

Supplying Additional Context

allowsdeniescheckanynoneauthorizecancannot 등의 속성과 블레이드의 @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...
}

Gate Responses

단순한 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 타입으로 리턴하는 것이 아니라
// 인가에 대한 전체 응답을 리턴할 수 있다

Customizing The HTTP Response Status

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();
});

Intercepting Gate Checks

모든 인가 체크 이전에 실행되는 메서드도 생성 가능하다 (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 속성과 마찬가지다

Inline Authorization

인가 처리를 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을 발생시킨다
profile
제어할 수 없는 것에 의지하지 말자

0개의 댓글