[컴][php] lumen 에서 Authorization 과 Authentication 사용하기

루멘 / php 프레임워크 / php framework lumen / laravel


lumen 에서 Authorization 과 Authentication


lumen 에서 Authorization 과 Authentication 을 고려할 때 다음 2가지만 만들어 주면 될 듯 하다. 아직 제대로 파악하지 못한 부분이 있어 틀린 부분이 있을 수 있다.

  1. AuthServiceProvider::boot() 에서는 Authorization, Authentication 과 관련된 설정을 해준다.
    • Authorization : 어떤 권한에 대한 정의, 예를 들면 'posting 할 수 있는 권한' 은 어떤 조건이 만족해야 하는지. 아래 source codes 에서 Gate::define() 으로 이것을 만들게 된다.
    • Authentication : 이건 이 사람이 누군인지를 인증하기 위해 어떻게 해라라고 만들어주면 된다. 그래서 인증이 된 사람이면, User 를 return 해주고, 그렇지 않으면 null 을 return 해주면 된다.
  2. App/Http/Middleware/Authenticate.php 에서 어떤 회원일때(guest 등) 어떤 Unauthorized 를 줄 것인지 정해서 code 를 작성하면 된다. 이것을 적용해서 어떤 controller 의 동작은 Login 한 유저만 접근하게 하고 싶다. 등은 Controller::__construct() 에서 이 controller 는 middleware 'auth' 를 호출한다 라고 정해주면 된다.
  3. Controller 에서 이제 "어떤 권한(authorized)" 을 가진 녀석이 이 일을 하고, 어떤 권한은 이 동작을 못하게 하는 등의 작업을 해주면 된다. Gate::allow, Gate::deny 등으로 할 수 있다.



bootstrap/app.php
$app->withFacades();
...
$app->routeMiddleware([
    'auth' => App\Http\Middleware\Authenticate::class,
]);
...
$app->register(App\Providers\AuthServiceProvider::class);



App\Providers\AuthServiceProvider.php

namespace App\Providers;

use App\User;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    ...
    /**
     * Boot the authentication services for the application.
     *
     * @return void
     */
    public function boot()
    {
        //  $this->registerPolicies();
       
        Gate::define('retrieve-new', function ($user, $request) {
            return true;    // anybody
        });

        // Here you may define how you wish users to be authenticated for your Lumen
        // application. The callback which receives the incoming request instance
        // should return either a User instance or null. You're free to obtain
        // the User instance via an API token or any other method necessary.

        $this->app['auth']->viaRequest('api', function ($request) {
            // 'api' is the key for customCreators of the AuthManager
            // and the callback function which must return a User instance or null
            // because the RequestGuard save the return value of callback function
            // to the $this->$user variable.
            // Thus, this function can be used for authorization.
            //
            // This callback should have check routine whether the this request
            // is authorized and if so, retrieving the User data

           
            $header = $request->header('Api-Token');

            if($header && $header == 'birds fly'){
                if ($header) {
                    return User::where('api_token', $header)->first();
                }
                return new User();
            }
            return null;

           
        });
    }
}



App/Http/Middleware/Authenticate.php
class Authenticate
{
    ...
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        if ($this->auth->guard($guard)->guest()) {
            return response('Unauthorized.', 401);
        }

        return $next($request);
    }
}


App/Http/Controller/NewEventController.php

namespace App\Http\Controllers;
 
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Gate;
use Illuminate\Http\Request;
use App\G5Member;

class NewEventController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {

        $this->middleware('auth', ['only'=>[
            'authenticate'
        ]]);
    }

    public function authenticate(Request $request)
    {
      if (Gate::allows('retrieve-new', $request)) {
        $this->validate($request, [
   
            'email' => 'required',
            'password' => 'required'
        ]);
   
       // check whether the User exists
       // ...
        if(is_null($isUser)){
            // a id/pw pair does not exist
            return response()->json(['status' => 'fail'],401);
        }

        // if exists
        // generate the temporary apiKey and use only for this session
        $apikey = base64_encode(str_random(40));
        User::where('mb_id', $request->input('email'))->update(['api_key' => "$apikey"]);;
        return response()->json(['status' => 'success','api_key' => $apikey]);
      }
   
    }
}


  • Gate::forUser(Auth::user())->allows(...
  • Gate::allows(... : current user 에 적용할때


Policy

policy 는 Guard 의 설정을 모아놓은 class 라 봐도 될 듯 하다. 주로 Model 이랑 관련해서 만들기는 하지만 꼭 Model::class 에 적용할 필요는 없다.

laravel 에서는 AuthServiceProvider::boot() 에서 $this->registerPolicies(); 를 호출해서 policy 들을 적용한다. 그런데 lumen 에서는 그렇지 않다..


// laravel source
class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        Post::class => PostPolicy::class,
    ];

    public function boot()
    {
        $this->registerPolicies();

        //
    }
}


lumen 에서는 아래처럼 적용하면 된다.

class AuthServiceProvider extends ServiceProvider
{

    public function boot()
    {
        Gate::policy(Post::class, PostPolicy::class);

        //
    }
}

laravel 에서는 아래 command 를 사용해서 Policy class 를 만들 수 있다. 하지만 lumen 에서는 안된다.
php artisan make:policy PostPolicy

policy class 의 작성법은 Authorization - Laravel를 참고하자.


Policy 사용예


<?php

namespace App\Policies;

use App\User;
use App\Product;

class ProductPolicy
{
    public function before(User $user, $ability)
    {
        if ($user->id == 'admin') {
            return true;
        }
    }
    /**
     * Determine if the given post can be updated by the user.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return bool
     */
    public function duplicate(User $user)
    {
        return $user->id == 'admin';
    }

    
}

class AuthServiceProvider extends ServiceProvider
{

    public function boot()
    {
        Gate::policy(Product::class, ProductPolicy::class);

        //
    }
}


// ProductHandleController.php
public function duplicate(Request $request){

    $this->validate($request, [
        'prod_id' => 'bail|integer|exists:product,id',
    ]);

    $user = Auth::user();
    if ($user->can('duplicate', Product::class)) {

        ...
    }
}

$user->can('duplicate', Product::class) 을 실행하면, Product::class 의 등록된 policy 를 찾고, 거기서 duplicate 가 있는지 찾게 된다.




References

  1. Authorization - Laravel - The PHP Framework For Web Artisans
  2. HTTP Routing - Lumen - PHP Micro-Framework By Laravel
  3. Authentication - Lumen - PHP Micro-Framework By Laravel
  4. How to Secure a REST API With Lumen
  5. Create Lumen REST API Authentication for the ToDo app

댓글 없음:

댓글 쓰기