커스텀 폴리시 매서드 추가하기 free

2019-09-03

애플리케이션을 만들다보면 사용자별로 다른 권한을 줘야하는 상황이 생깁니다. 대표적인 예가 게시물을 작성한 사람과 관리자에게만 게시물의 수정 및 삭제 권한을 주는 것이죠. 대부분의 애플리케이션에서 이와 같은 상황이 나타나기 때문에 라라벨은 권한을 부여하고 확인하는(이제부터는 인가라고 부르겠습니다) 편리한 기능을 제공합니다.


라라벨은 게이트(Gate)와 폴리시(Policy) 두 가지의 인가 방식을 제공합니다. 둘의 차이는 라우트를 정의할 때 익명함수로 정의하는 것과 컨트롤러를 작성하는 것의 차이와 같다고 보시면 됩니다. PostController가 Post 자원에 대한 다양한 액션을 한 데 모아둔 것 처럼, Post에 대한 다양한 행위에 대한 권한 확인 기능을 PostPolicy에 모읍니다.


폴리시를 생성할 때 모델을 지정하면 기본적인 CRUD 폴리시 매서드를 포함해서 생성해줍니다. 컨트롤러를 생성할 때 리소스 컨트롤러를 만들면서 모델을 지정하는 것과 비슷합니다.


php artisan make:policy PostPolicy --model=Post

위와 같이 하면 컨트롤러 매서드에 대응하는 폴리시 매서드가 다음과 같이 자동으로 생성됩니다.(물론 내용은 직접 채워넣어야 합니다.)


Controller MethodPolicy Method
showview
createcreate
storecreate
editupdate
updateupdate
destroydelete

현실은 더 복잡하다


어차피 모든 요청이 컨트롤러를 통해 처리되니까 컨트롤러 매서드별로 폴리시가 있으면 충분해 보입니다. 하지만 현실은 언제나 생각보다 복잡해서 문제입니다. 1일 1식 라라벨의 지난 글을 읽을 수 있는 웹사이트를 예로 들어볼게요.


1일 1식 라라벨은 우선 글을 읽을 수 있는 권한이 살짝 복잡합니다.



  1. 배포되지 않은 글은 발행자만 볼 수 있습니다.

  2. 배포된 글은 누구든 볼 수는 있습니다.

  3. 배포된 공개글은 누구든 전문을 볼 수 있습니다.

  4. 배포된 유료구독자 전용글은 유료 구독한 사람만 전문을 볼 수 있습니다. 유료 구독한 사람이 아닌 경우 일부만 볼 수 있습니다.


우선 1번과 2번은 간단히 처리할 수 있습니다.


// app/Policies/PostPolicy
public function view(User $user, Post $post)
{
if($post->status === 'draft' &&
$user->id != $post->user_id) {
return false;
}

return true;
}

3번과 4번이 문젠데요. 보긴 보는데 누군 전문을 보고 누군 일부만 볼 수 있는 권한이 있는 것이죠. 그래서 단순히 view 매서드에서 true, false를 반환하는 것으로 한꺼번에 처리하기가 곤란합니다.


그래서 아래와 같이 매서드를 추가했습니다.


public function viewPaid(User $user, Post $post)
{
// 로직
}

이제 view와 viewPaid를 조합하면 앞의 모든 요구사항을 처리할 수 있습니다. 뷰에서 viewPaid()를 통과하면 전문을 보여주고, 통과하지 못하면 일부만 보여주면 되겠죠.


viewPaid()는 어떻게 검사하지?


viewPaid() 같이 폴리시 매서드가 두 단어 이상으로 되어 있을 때는 권한 검사시 각 단어를 하이픈(-)으로 연결하면 됩니다.


if( $user->can('view-paid', $post)) {
}

간단한 것이지만 매뉴얼에는 나오지 않는 내용이니 잘 쟁여두었다 활용하세요~ :)


1일 1식 라라벨 46호

2019년 9월 3일


이현석

바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서를 쓰고, 클린 아키텍처 인 PHP를 번역했습니다. 2020년에 출간될 Laravel Up & Running 2nd Edition을 번역하고 있습니다.