XE 3 (Xpressengine 3)에서 Passport 사용하기

사용자 인증을 손쉽게 사용할 수 있게 해주는 패키지 Passport를 XE3 (Xpressengine 3) 에 적용하는 방법을 소개합니다.

 

설치하기

$ composer require laravel/passport

에러가 발생한다면 아래와 같이 해결해줘야 합니다.

$ composer require paragonie/random_compat=~2.0
$ composer require laravel/passport=^4.0

Your requirements could not be resolved to an installable set of packages · Issue #774 · laravel/passport

 

서버스 프라이드 등록

\config\app.php 파일

'providers' => [
				/**
         * Passport
         */
        Laravel\\Passport\\PassportServiceProvider::class,
]

PassportServiceProvider 를 등록시켜줍니다.

 

마이그레이션 실헹

Passport 마이그레이션을 실행하면 애플리케이션에서 필요한 클라이언트와 엑세스 토큰을 저장하는 테이블이 생성됩니다.

$ php artisan vendor:publish --tag=passport-migrations

마이그레이션 테이블 생성

  • oauth_auth_codes
  • oauth_access_tokens
  • oauth_refresh_tokens
  • oauth_clients
  • oauth_personal_access_clients

위 테이블에서 사용하는 user_id 가 uuid 를 사용하도록 변경해줘야 합니다.

 

Passport Install

$ php artisan passport:install

Personal Access Client, Password Grant Client 생성합니다.

 

유저 모델에 Trait 추가

\\core\\src\\Xpressengine\\User\\Models\\User모델에 Laravel\\Passport\\HasApiTokens Trait 를 추가해주세요.
해당 Trait는 모델에 인증된 사용자의 토큰과 범위를 확인하기 위한 몇 가지 헬퍼 메소드를 제공하고 있습니다.

\core\src\Xpressengine\User\Models\User.php 파일

<?php

namespace Xpressengine\\User\\Models;

....
use Laravel\\Passport\\HasApiTokens;

class User extends DynamicModel implements
    UserInterface,
    AuthenticatableContract,
    CanResetPasswordContract,
    AuthorizableContract
{
    use Notifiable, Authenticatable, Authorizable, HasApiTokens;
}

 

Passport 라우트 등록

AuthServiceProvider 클래스의 Boot 메소드에 Passport::route 메소드를 호출해줘야 합니다.
이 메소드는 엑세스 토큰을 발급하는 라우트와 엑세스 토큰, 클라이언트 그리고 개인용 액새스 토큰을 해체하는 라우트를 등록해줍니다.

\app\Providers\AuthServiceProvider.php 파일

<?php

namespace App\\Providers;

use Illuminate\\Support\\Facades\\Gate;
use Illuminate\\Foundation\\Support\\Providers\\AuthServiceProvider as ServiceProvider;
use Laravel\\Passport\\Passport;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\\Model' => 'App\\Policies\\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();
        Passport::routes();
    }
}

 

Passport Config 등록

config/auth.php 설정 파일에서 guard - api 인증 driver 옵션을 passport 로 설정해 줍니다.
이렇게 하면 인증 API Request 유입될 때 어플리케이션이 Passport의 TokenGuard 를 사용합니다.

\config\auth.php 파일

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

 

Passport 배포하기

Passport를 실서버에 맨 처음 배포 시 passport:keys 명령어를 실행해줘야 한다.
토큰을 생성하기 위해서 passport에서 필요한 암호된 키를 생성합니다. 생성된 키는 일반적으로 소스 컨트롤러에 유지되지 않습니다.

$ php artisan passport:keys

 

로그인 API

토큰 기반 인증 서비스에서 사용할 엑세스 토큰(access token)을 발급받습니다.

route.php 파일

Route::group([ 'prefix' => 'api/', 'middleware' => 'api'], function () {
    Route::post('/login', ['as' => 'spark-auth::login', 'uses' => 'Sparkweb\\XePlugin\\SparkAuth\\Controller@login']);
});

 

Controller.php 파일

public function login(Request $request)
{
    $this->validate($request, [
        'email' => 'required',
        'password' => 'required'
    ]);

    $credentials = $request->only('email', 'password');

    $credentials['email'] = trim($credentials['email']);

    $credentials['status'] = [User::STATUS_ACTIVATED, User::STATUS_PENDING_ADMIN, User::STATUS_PENDING_EMAIL];

    if (app('auth')->attempt($credentials, $request->has('remember'))) {
        $user = \\Auth::user();
        $token = $user->createToken($user->email.'-'.now());

        return XePresenter::makeApi([
            'user' => $user,
            'token' => $token->accessToken
        ]);
    }
}

 

Response Body


 

 

인증 API (auth:api)

발급받은 엑세스 토큰(access token)을 Authorization 헤더에 담아서 보냅니다.

 

route.php

Route::group([ 'prefix' => 'api/', 'middleware' => 'api'], function () {
    Route::group(['middleware' => 'auth:api'], function () {
        Route::get('/user', ['as' => 'spark-auth::user', 'uses' => 'Sparkweb\\XePlugin\\SparkAuth\\Controller@user']);
    });
});

 

Controller.php

public function user(Request $request)
{
    return Auth::user();
}

 

Haeder

 

Response Body

 

적용하면서 발생한 에러 해결하기

 

Replicating claims as headers is deprecated and will removed from v4.0. Please manually set the header if you need it replicated.

해결방법

Updating lcobucci/jwt (3.3.1 => 3.3.3):

composer require lcobucci/jwt=3.3.3

 

 

middleware - auth:api 사용하는 라우트 통신 시 로그인 페이지로 리다이렉트 되는 문제

해결방법

Passport에 의해서 보호되는 라우트를 호출할 때, 애플리케이션의 API 사용자는 그들의 요청-request의 Authorization 헤더에 Bearer 토큰으로 엑세스 토큰을 지정해야 합니다. 또한 Accept 헤더에 application/json 을 설정해줘야 합니다.

통신 시 헤더에 아래 값을 필수적으로 입력해줘야 합니다.

Header
- Authorization: Bearer token
- Accept: application/json

HTTP Header Authorization 헤더에 넣어서 보낸 Bearer 토큰이 유실되는 현상. 프로젝트 루트에 있는 .htaccess 파일을 수정해서 문제를 해결했습니다.

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

 

  • share