Laravel 인가

1 개요[ | ]

Crystal Clear action info.png 작성 중인 문서입니다.
Authorization
인가

https://laravel.com/docs/11.x/authorization

2 소개[ | ]

Laravel은 빌트인 인증 서비스 외에도 주어진 리소스에 대해 사용자의 액션을 인가할 수 있는 간단한 방법을 제공합니다. 예를 들어, 사용자가 인증되었다 하더라도 애플리케이션에서 관리하는 특정 Eloquent 모델이나 데이터베이스 레코드를 업데이트하거나 삭제할 권한이 없을 수도 있습니다. Laravel의 인가 기능은 이러한 유형의 인가 확인을 관리하는 쉬운 방법을 제공합니다.

Laravel은 주로 두 가지 방식으로 액션을 인가합니다: 게이트(gate)정책(policy). 게이트와 정책을 라우트와 컨트롤러처럼 생각할 수 있습니다. 게이트는 간단한 클로저 기반 접근 방식을 제공하는 반면, 정책은 특정 모델이나 리소스를 중심으로 로직을 그룹화합니다. 이 문서에서는 먼저 게이트를 알아본 다음 정책을 살펴보겠습니다.

애플리케이션을 구축할 때 게이트만 사용하거나 정책만 사용하는 것을 선택할 필요는 없습니다. 대부분의 애플리케이션은 게이트와 정책이 혼합된 형태를 포함할 가능성이 높으며, 이는 전혀 문제가 되지 않습니다! 게이트는 관리자 대시보드를 보는 것과 같이 특정 모델이나 리소스와 관련이 없는 액션에 가장 적합합니다. 반면, 정책은 특정 모델이나 리소스에 대한 액션을 인가하고자 할 때 사용해야 합니다.

3 게이트[ | ]

3.1 게이트 작성[ | ]

Warning

게이트는 Laravel의 인가 기능의 기초를 배우는 훌륭한 방법입니다. 그러나 견고한 Laravel 애플리케이션을 구축할 때는 인가 규칙을 조직화하기 위해 정책을 사용하는 것을 고려해야 합니다.

게이트는 단순히 사용자가 주어진 작업을 수행할 권한이 있는지를 결정하는 클로저입니다. 일반적으로 게이트는 Gate 파사드를 사용하여 App\Providers\AppServiceProvider 클래스의 boot 메소드 내에서 정의됩니다. 게이트는 항상 사용자 인스턴스를 첫 번째 인수로 받고, 선택적으로 관련 있는 Eloquent 모델과 같은 추가 인수를 받을 수 있습니다.

이 예제에서는 사용자가 주어진 App\Models\Post 모델을 업데이트할 수 있는지 여부를 결정하는 게이트를 정의합니다. 게이트는 사용자의 id를 게시물을 작성한 사용자의 user_id와 비교하여 이를 수행합니다:

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;

/**
 * 애플리케이션 서비스를 부트스트랩합니다.
 */
public function boot(): void
{
    Gate::define('update-post', function (User $user, Post $post) {
        return $user->id === $post->user_id;
    });
}

컨트롤러와 마찬가지로, 게이트도 클래스 콜백 배열을 사용하여 정의할 수 있습니다:

use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;

/**
 * 애플리케이션 서비스를 부트스트랩합니다.
 */
public function boot(): void
{
    Gate::define('update-post', [PostPolicy::class, 'update']);
}

3.2 액션 인가[ | ]

게이트를 사용하여 액션를 승인하려면, Gate 파사드가 제공하는 allows 또는 denies 메소드를 사용해야 합니다. 현재 인증된 사용자를 이 메소드에 전달할 필요는 없습니다. Laravel이 게이트 클로저로 사용자를 자동으로 전달하기 때문입니다. 인가가 필요한 액션을 수행하기 전에 애플리케이션의 컨트롤러에서 게이트 인가 메소드를 호출하는 것이 일반적입니다:

<?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
{
    /**
     * 주어진 포스트를 업데이트합니다.
     */
    public function update(Request $request, Post $post): RedirectResponse
    {
        if (! Gate::allows('update-post', $post)) {
            abort(403);
        }

        // 포스트를 업데이트합니다...

        return redirect('/posts');
    }
}

현재 인증된 사용자 외에 다른 사용자가 액션을 수행할 수 있는지 확인하려면 Gate 파사드의 forUser 메소드를 사용할 수 있습니다:

if (Gate::forUser($user)->allows('update-post', $post)) {
    // 사용자가 포스트를 업데이트할 수 있습니다...
}

if (Gate::forUser($user)->denies('update-post', $post)) {
    // 사용자가 포스트를 업데이트할 수 없습니다...
}

한 번에 여러 액션을 인가하려면 any 또는 none 메소드를 사용할 수 있습니다:

if (Gate::any(['update-post', 'delete-post'], $post)) {
    // 사용자가 포스트를 업데이트하거나 삭제할 수 있습니다...
}

if (Gate::none(['update-post', 'delete-post'], $post)) {
    // 사용자가 포스트를 업데이트하거나 삭제할 수 없습니다...
}
예외를 던지며 인가

액션을 인가하려 시도하고 사용자가 주어진 행위를 수행할 수 없는 경우 Illuminate\Auth\Access\AuthorizationException을 자동으로 던지려면 Gate 퍼사드의 authorize 메소드를 사용할 수 있습니다. AuthorizationException 인스턴스는 Laravel에 의해 자동으로 403 HTTP 응답으로 변환됩니다:

Gate::authorize('update-post', $post);

// 액션이 인가되었습니다...
추가 컨텍스트 제공

인가 기능을 위한 게이트 메소드(allow, deny, check, any, none, authorize, can, cannot)와 인가 Blade 지시문(@can, @cannot, @canany)은 두 번째 인수로 배열을 받을 수 있습니다. 이 배열 요소는 게이트 클로저에 매개변수로 전달되며, 인가 결정을 내릴 때 추가 컨텍스트로 사용할 수 있습니다:

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])) {
    // 사용자가 포스트를 생성할 수 있습니다...
}

3.3 게이트 응답[ | ]

지금까지는, 단순한 불리언 값을 반환하는 게이트만 살펴보았습니다. 하지만 때로는 오류 메시지를 포함한 더 자세한 응답을 반환하고 싶을 때가 있습니다. 이를 위해 게이트에서 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.');
});

게이트에서 인가 응답을 반환할 때에도 Gate::allows 메소드는 여전히 단순한 불리언 값을 반환하지만, Gate::inspect 메소드를 사용하여 게이트에서 반환된 전체 인가 응답을 얻을 수 있습니다:

$response = Gate::inspect('edit-settings');
 
if ($response->allowed()) {
    // 액션이 허가되었습니다...
} else {
    echo $response->message();
}

게이트에서 인가되지 않은 액션에 대해 AuthorizationException을 던지는 Gate::authorize 메소드를 사용할 때, 인가 응답에서 제공한 오류 메시지는 HTTP 응답으로 전달됩니다:

Gate::authorize('edit-settings');
 
// 액션이 인가되었습니다...
HTTP 응답 상태 커스터마이징

게이트를 통해 액션이 거부될 때 403 HTTP 응답이 반환되지만, 때로는 대체 HTTP 상태 코드를 반환하는 것이 유용할 수 있습니다. 실패한 인가 확인에 대한 HTTP 상태 코드를 커스터마이징하려면 Illuminate\Auth\Access\Response 클래스의 denyWithStatus 정적 생성자를 사용할 수 있습니다:

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

리소스를 404 응답으로 숨기는 것은 웹 애플리케이션에서 매우 흔한 패턴이기 때문에, 이를 위한 편리한 메소드인 denyAsNotFound가 제공됩니다:

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

3.4 게이트 체크 가로채기[ | ]

3.5 인라인 인가[ | ]

4 정책 생성[ | ]

4.1 정책 생성하기[ | ]

4.2 정책 등록하기[ | ]

5 정책 작성[ | ]

5.1 정책 메소드[ | ]

5.2 정책 응답[ | ]

5.3 모델 없는 메소드[ | ]

5.4 게스트 사용자[ | ]

5.5 정책 필터[ | ]

6 정책을 사용한 액션 인가[ | ]

6.1 사용자 모델을 통해[ | ]

6.2 게이트 파사드를 통해[ | ]

6.3 미들웨어를 통해[ | ]

6.4 Blade 템플릿을 통해[ | ]

6.5 추가 컨텍스트 제공[ | ]

7 인가 & Inertia[ | ]

문서 댓글 ({{ doc_comments.length }})
{{ comment.name }} {{ comment.created | snstime }}