[Laravel] Authorization 구현 및 사용자별 권한 주기
Authorization
Policies
경로 app/Policies
포스트 같은 특정 콘텐츠에 대한 생성/수정/삭제 에 대한 권한을 제공
php artisan make:policy PostPolicy
<?php
namespace App\Policies;
use App\Models\Auth\User\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class PostPolicy
{
use HandlesAuthorization;
public function __construct()
{
//
}
}
<?php
namespace App\Policies;
use App\Models\Auth\User\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class PostPolicy
{
use HandlesAuthorization;
public function __construct()
{
//
}
//policy에 before가 있을 경우 가장 먼저 실행된다.
public function before($user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
}
php artisan make:policy PostPolicy --model=Post
<?php
namespace App\Policies;
use App\Models\Auth\User\User;
use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;
class PostPolicy
{
use HandlesAuthorization;
public function view(User $user, Post $post){}
public function create(User $user){}
public function update(User $user, Post $post){}
public function delete(User $user, Post $post){}
}
Registering Policies
<?php
namespace App\Providers;
use App\Post;
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
Post::class => PostPolicy::class,
// Without models policies
'backend' => BackendPolicy::class,
];
}
Writing Policies이전에 만든 policy를 재정의한다.
<?php
namespace App\Policies;
use App\User;
use App\Post;
class PostPolicy
{
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
action with model
if ($user->can('update', $post)) {
//
}
action without model
use App\Post;
if ($user->can('create', Post::class)) {
// Executes the ""create"" method on the relevant policy...
}
use Illuminate\Support\Facades\Auth;
// Get the currently authenticated user...
$user = Auth::user();
// Get the currently authenticated user's ID...
$id = Auth::id();
echo PHP_EOL.$user->id;
echo PHP_EOL.$user->email;
echo PHP_EOL.$user->password;
echo PHP_EOL.$user->remember_token;
echo PHP_EOL.$user->hasRole(""administrator"") ;"
강제 로그인
..
protected function guard()
{
return \Auth::guard();
}
$this->guard()->login($user);
Auth (권한부여하기)
참조 : https://laravel.com/docs/10.x/authentication
php artisan make:auth
roles 테이블을 생성한다.
roles 테이블은 role 에 대한 이름을 정의한다(예, user, admin, ...)
php artisan make:migration create_roles_table --create=roles
user-roles 테이블을 생성한다.
user-roles 테이블에는 user 와 role을 맵핑한다(user_id: 1, role_id: 1)
php artisan make:migration create_users_roles_table --create=users_roles
socialite 테이블 생성
소셜로그인에 사용될때 사용하는 것이다. 이 부분은 소셜로그인 편에서 새로 다루겠습니다.
php artisan make:migration create_social_accounts_table --create=social_accounts
composer require laravel/socialite
기존 경로(App\User -> App\Models\Auth\User\User) 로 경로를 변경함에 따라 다른 곳의 경로도 변경
- config/auth.php
'providers' => [
'users' => [
'driver' => 'eloquent',
// 'model' => App\Models\User::class, //변경전
'model' => App\Models\Auth\User\User::class, // 변경후
],
],
기존 Controllers/Auth 에 존재하는 파일을 수정/추가한다.
ForgotPasswordController.php
LoginController.php
RegisterController.php
ResetPasswordController.php
SocialLoginController.php (추가 for social Login)
ConfirmController.php (추가 현재는 구현되지 않았으나 회원가입시 확인메일 발송처리단)
AppController.php (SocialLoginController 와 동일하나 앱에서 로그인 처리시 사용)
각각에 이벤트 달기
app/Providers/EventServiceProvider.php
app/Events\Auth\SocialLogin.php
app/Listeners/Auth/LoginListener.php
app/Listeners/Auth/LogoutListener.php
app/Listeners/Auth/RegisteredListener.php
app/Listeners/Auth/SocialLoginListener.php
socialite
config/services.php
.env
관리자단 구성
- 관리자단을 구성하기 위해서는 먼저 회원별 roll이 존재 하여야 한다. (상기 회원 구성에서 roll 참조)
- middleware 구성
일반적인 방법
- Create a Midlleware
php artisan make:middleware AnyNameYouWant
public function handle($request, Closure $next)
{
if (\Auth::user()->role == 'admin') {
return $next($request);
}
return redirect('home');
}
- Use this in Kernel
app > Http > Kernel.php 파일을 아래와 같이 admin이라는 route용 미들웨어를 추가합니다..
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
..........
'admin' => \App\Http\Middleware\AnyNameYouWant::class,
]
- Protect your routes
이제는 route 파일에서 위에정의한 admin을 middleware로 처리하면 처리됩니다.
Route::get('admin/profile', function () {
//
})->middleware('admin');
route->kernel->middleware 로 단순
내가 사용하는 방법
위의 방법은 각각의 롤마다 처리해야 되는데 roll이 다양할 경우는 조금 번그로와서 아래와 같이 처리하였습니다.
Create a Midlleware
CheckRole이라는 Middleware를 만든다.
app > Http > Middleware > CheckRole.php
php artisan make:middleware CheckRole
<?php
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
public function handle($request, Closure $next, $role)
{
if (!$request->user()) {
return redirect('login');
}
if (!$request->user()->hasRole($role)) {
return redirect('/');
}
return $next($request);
}
}
Use this in Kernel
app > Http > Kernel.php
protected $middlewareGroups = [
..........
'admin' => [ // admin을 만들어 준다.
'role:administrator',
],
];
..........
protected $routeMiddleware = [
..........
'role' => \App\Http\Middleware\CheckRole::class, // role을 기존에 만들어 두었던 CheckRole로 정의한다.
];
Protect your routes
routes.php에서 아래와 같이 정의하여 사용하면 된다.
Route::get('admin/profile', function () {
//
})->middleware('admin');
여러가지의 권한을 부여할 경우
AuthorizesRequests를 사용하여 액션별 권한을 부여
- Create a Midlleware
php artisan make:middleware Authorize
https://laravel.com/docs/5.7/middleware 참조
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Authorize
{
public function handle($request, Closure $next, $ability, $attributes = [])
{
$this->authorize($ability, $attributes);
return $next($request);
}
}
Policy 설정
php artisan make:policy AdminPolicy
<?php
namespace App\Policies;
use App\Models\Auth\User\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class AdminPolicy
{
use HandlesAuthorization;
public function __construct()
{
//
}
}
아래와 같이 변경한다.
public function view(User $user) // , Author $author
{
return $user->hasRoles(['administrator']);
}
AuthServiceProvider 에 등록policy를 Service Provider 에 등록 (이것 없이 바로 커널에 적용해도 됨)
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use App\Policies\AdminPolicy;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
'admin' => AdminPolicy::class
];
public function boot()
{
$this->registerPolicies();
}
}
Use this in Kernel
이제 만들어진 룰을 커널에 적용해 보자
protected $middlewareGroups = [
'admin' => [
'auth',
'authorize:view,admin',
],
]
..........
protected $routeMiddleware = [
'authorize' => \App\Http\Middleware\Authorize::class,
];
'미들웨어 명' => [
'routeMiddleware 에 정의된 파트',
'outeMiddleware 에 정의된 파트:인자값1,인자값2',
],
Protect your routes.
Route::get('admin/profile', function () {
//
})->middleware('admin');
이해를 돕기위해 실제실행 되는 순서를 간략하게 설명해 드립니다.
routesRoute::get('admin/profile', function () { }) -> middleware('admin');middlewareGroup의 admin호출
kernel$middlewareGroups = [ 'admin' => [ 'authorize:view,admin', ]..],
kernelprotected $routeMiddleware = [ 'authorize' => \App\Http\Middleware\Authorize::class,];App\Http\Middleware\Authorize 호출
Authorize.php
public function handle($request, Closure $next, $ability, $attributes = []){
$this->authorize($ability, $attributes);
} //authorize에 view, admin 으로 인자값 전달