lumen 에서 Authorization 과 Authentication
lumen 에서 Authorization 과 Authentication 을 고려할 때 다음 2가지만 만들어 주면 될 듯 하다. 아직 제대로 파악하지 못한 부분이 있어 틀린 부분이 있을 수 있다.
- AuthServiceProvider::boot() 에서는 Authorization, Authentication 과 관련된 설정을 해준다.
- Authorization : 어떤 권한에 대한 정의, 예를 들면 'posting 할 수 있는 권한' 은 어떤 조건이 만족해야 하는지. 아래 source codes 에서 Gate::define() 으로 이것을 만들게 된다.
- Authentication : 이건 이 사람이 누군인지를 인증하기 위해 어떻게 해라라고 만들어주면 된다. 그래서 인증이 된 사람이면, User 를 return 해주고, 그렇지 않으면 null 을 return 해주면 된다.
- App/Http/Middleware/Authenticate.php 에서 어떤 회원일때(guest 등) 어떤 Unauthorized 를 줄 것인지 정해서 code 를 작성하면 된다. 이것을 적용해서 어떤 controller 의 동작은 Login 한 유저만 접근하게 하고 싶다. 등은 Controller::__construct() 에서 이 controller 는 middleware 'auth' 를 호출한다 라고 정해주면 된다.
- 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 가 있는지 찾게 된다.
댓글 없음:
댓글 쓰기