JWTAuth をインストール・設定
$ composer require tymon/jwt-auth:dev-develop --prefer-source
※2018/06/14現在、laravel5.5の場合jwt-authの開発版を入れないと設定中にエラーが出てしまうので開発版を入れます。
'providers' => [ ・・・ /* * Package Service Providers... */ Tymon\JWTAuth\Providers\LaravelServiceProvider::class, ・・・ 'aliases' => [ ・・・ 'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class, 'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class
config/app.phpにJWTAuthをプロバイダ登録し、エイリアスを設定します。
laravelは外部パッケージを使用する場合、このプロバイダ登録をすることによって有効化できる仕組みになっています。
$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider" Copied File [\vendor\tymon\jwt-auth\config\config.php] To [\config\jwt.php] Publishing complete.
次に、このベンダーパブリッシュコマンドを叩きます。
これも外部パッケージを使用するときの初期設定のようなもので、当該パッケージ用の設定ファイルなどが生成されます。
$ php artisan jwt:secret jwt-auth secret [xxxxxxxxxxxxxxxxxxxxxxxxxxxxx] set successfully.
続いて今度はJWTAuth用のシークレットを自動生成します。
トークンを発行する際のハッシュキーのようなものですね。
php artisan jwt:secret とすることで.envファイルに自動追記されます。
protected $routeMiddleware = [ ・・・ 'jwt.auth' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class, 'jwt.refresh' => \Tymon\JWTAuth\Http\Middleware\RefreshToken::class, ];
最後に、ルーティングでミドルウェアとして使用できるように、Kernel.phpに上記を追記します。
ルーティング設定
laravelには「ミドルウェア」という概念があります。
これは
・ユーザからのリクエストがコントローラに入る前
・コントローラのレスポンスがユーザに返る前
に何がしかの処理をかけることができる仕組みで、ルーティングと組み合わせて設定することができます。
ページURLごと、あるいはコントローラごとに共通処理をまとめて記述することができるので、認証処理にはうってつけの機能であるわけです。
Route::group(['middleware' => 'api'], function () { Route::group(['middleware' => ['jwt.auth']], function() { Route::resource('users', 'UsersController'); }); });
api.phpのルーティング設定を上記のようにします。
これだけで、/usersのREST APIに認証をかけることができます。
$ curl -X GET http://127.0.0.1:8000/api/users {"status":401,"errors":"Token not provided"}
この通り、401エラーが返るようになりました。
ログイン・ログアウト処理を行うコントローラを作成
$ php artisan make:controller AuthenticateController
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Facades\JWTAuth; use App\User; class AuthenticateController extends Controller { public function authenticate(Request $request) { // grab credentials from the request $credentials = $request->only('email', 'password'); try { // attempt to verify the credentials and create a token for the user if (! $token = JWTAuth::attempt($credentials)) { return response()->json(['error' => 'invalid_credentials'], 401); } } catch (JWTException $e) { // something went wrong whilst attempting to encode the token return response()->json(['error' => 'could_not_create_token'], 500); } $user = User::where('email', $request->email)->first(); // all good so return the token return response()->json(compact('user', 'token')); } public function getCurrentUser() { $user = JWTAuth::parseToken()->authenticate(); return response()->json(compact('user')); } public function logout() { }
}
このコントローラが認証処理を担当します。
Route::group(['middleware' => 'api'], function () { Route::group(['middleware' => ['jwt.auth']], function() { Route::resource('users', 'UsersController'); Route::get('me', 'AuthenticateController@getCurrentUser'); Route::get('logout', 'AuthenticateController@logout')->middleware('jwt.refresh'); }); Route::post('authenticate', 'AuthenticateController@authenticate'); });
api.phpのルーティングに認証関連を追記します。
authenticate(ログイン)は認証の外に置きます。
また、UserモデルをJWTAuthに対応させる必要があります。
<?php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { use Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; /** * Get the identifier that will be stored in the subject claim of the JWT. * * @return mixed */ public function getJWTIdentifier() { return $this->getKey(); } /** * Return a key value array, containing any custom claims to be added to the JWT. * * @return array */ public function getJWTCustomClaims() { return []; } }
JWTSubjectをimplementして、getJWTIdentifierメソッドとgetJWTCustomClaimsを実装します。
これでログインできるようになりました。
テストユーザでログインしてみます。
$ curl -X POST http://127.0.0.1:8000/api/authenticate -d "email=shdfdfdawn.fahey@example.com&password=secret" {"user":{"id":6,"name":"Kirstedfdfn Lemke","email":"shdfdfdawn.fahey@example.com","created_at":"2018-06-10 08:31:10","updated_at":"2018-06-13 13:58:55"},"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xMjcuMC4wLjE6ODAwMFwvYXBpXC9hdXRoZW50aWNhdGUiLCJpYXQiOjE1MjkwNjQ2NTAsImV4cCI6MTUyOTA2ODI1MCwibmJmIjoxNTI5MDY0NjUwLCJqdGkiOiJlcEJUUzU0VkFIMWpCY3RuIiwic3ViIjo2LCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.RWyktSNVaOJgxyZnEfTo1Sq__3ztOQ7THK0e5T1c1Ms"}
ログインに成功すると、このようにトークンが取得できます。
このトークンをヘッダに含めてリクエストすることで、認証を通過することができます。
$ curl -X GET localhost:8000/api/users -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xMjcuMC4wLjE6ODAwMFwvYXBpXC9hdXRoZW50aWNhdGUiLCJpYXQiOjE1MjkwNjQ2NTAsImV4cCI6MTUyOTA2ODI1MCwibmJmIjoxNTI5MDY0NjUwLCJqdGkiOiJlcEJUUzU0VkFIMWpCY3RuIiwic3ViIjo2LCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.RWyktSNVaOJgxyZnEfTo1Sq__3ztOQ7THK0e5T1c1Ms'
curlだとちょっと長くて煩雑に見えますが、このような形です。
これでユーザ一覧が取得できるようになりました。
$ curl -X GET http://127.0.0.1:8000/api/logout -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xMjcuMC4wLjE6ODAwMFwvYXBpXC9hdXRoZW50aWNhdGUiLCJpYXQiOjE1MjkwNjQ2NTAsImV4cCI6MTUyOTA2ODI1MCwibmJmIjoxNTI5MDY0NjUwLCJqdGkiOiJlcEJUUzU0VkFIMWpCY3RuIiwic3ViIjo2LCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.RWyktSNVaOJgxyZnEfTo1Sq__3ztOQ7THK0e5T1c1Ms'
ログアウトはこのように。