3
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel5.5こと始め 〜10. APIへのJWTAuth認証の追加〜

Last updated at Posted at 2018-07-14

内容

以下の順番にまとめます。
1. MacへのXAMPP+Laravelインストール
2. ユーザログイン機能の追加
[3. MVCとルーティングの説明]
(https://qiita.com/sonrisa/items/809adf872e6fb3657f81)
[4. ユーザリストの表示]
(https://qiita.com/sonrisa/items/929486929ed8d851a24e)
[5. ユーザリストのペジネーション表示]
(https://qiita.com/sonrisa/items/86efb8caebe207ab8fa8)
6. ユーザ管理APIの追加
7. Vue.jsとAPIベースのユーザ管理アプリの追加準備
8. Vue.jsとAPIベースのユーザ管理アプリの追加
[9. Vue.jsとAPIベースのユーザ管理アプリへのペジネーション追加]
(https://qiita.com/sonrisa/items/d58c56b638924d8c6810)
[10. APIへのJWTAuth認証の追加]
(https://qiita.com/sonrisa/items/97c1f3e8491f76dc2ce2) ←いまここ
11. Vue.jsとAPIベースのユーザ管理アプリへの認証の追加

10. APIへのJWTAuth認証の追加

home2へのアクセス時にログインを求められますが、APIには認証の実装がなされておらずAPIアクセスは誰でもできてしまいますので、このままでは問題です。そのため、home2へのアクセスは誰でもできるようにし、APIアクセスにJWTAuthを使って認証の機能を実装します。その後、次ページでVue.jsで実装されたSPA画面上でログインを実装することとします。

10.1 URI「home2」の認証を削除

認証はルーティング部分で設定していますので、「routes/web.php」を編集し、home2に認証なしでアクセスできるようにします。

routes/web.php
...()
//Route::middleware('auth')->get('/home2', function () {
//    return view('home2');
//})->name('home2');

Route::get('/home2', function () {
    return view('home2');
});

「php artisan serve」を実行して、「http://localhost:8000/home2 」にアクセスし、ログアウトしてもアクセスできることを確認します。

スクリーンショット 2018-07-16 23.20.58.png

10.2 APIへのJWTAuth認証の追加

1. JWTAuthのインストール

Composerコマンドを実行してJWTAuthをインストールします。

$ composer require tymon/jwt-auth
Using version ^0.5.12 for tymon/jwt-auth
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 4 installs, 0 updates, 0 removals
  - Installing symfony/polyfill-util (v1.8.0): Loading from cache
  - Installing symfony/polyfill-php56 (v1.8.0): Loading from cache
  - Installing namshi/jose (7.2.3): Loading from cache
  - Installing tymon/jwt-auth (0.5.12): Loading from cache
namshi/jose suggests installing phpseclib/phpseclib (Allows to use Phpseclib as crypto engine, use version ^2.0.)
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nunomaduro/collision
Package manifest generated successfully.

2. 「config/app.php」への設定

下記の通り、JWTAuthのprovidersとaliasesを設定します。

config/app.php
... 中略
    'providers' => [
... 中略
        Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
    ],
... 中略
    'aliases' => [
... 中略
        'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
        'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
    ],
];

3. 「app/Http/Kernel.php」への設定

下記の通り、ルーティングでJWTAuthが使えるように設定します。

app/Http/Kernel.php
... 中略
    protected $routeMiddleware = [
	'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
	'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
	'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
	'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
	'can' => \Illuminate\Auth\Middleware\Authorize::class,
	'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
	'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
	'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,

	'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,	// 追加
	'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class, // 追加
    ];
}

4. JWTAuthの設定ファイル作成

以下のコマンドを実行して「config/jwt.php」ファイルを作成します。

$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
Copied File [/vendor/tymon/jwt-auth/src/config/config.php] To [/config/jwt.php]
Publishing complete.

5. 秘密鍵の作成

以下のコマンドを実行して秘密鍵の生成を試みます。

$ php artisan jwt:generate

   ReflectionException  : Method Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() does not exist

  at /Users/Retina/userauth/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:135
    131|             $callback = explode('::', $callback);
    132|         }
    133| 
    134|         return is_array($callback)
  > 135|                         ? new ReflectionMethod($callback[0], $callback[1])
    136|                         : new ReflectionFunction($callback);
    137|     }
    138| 
    139|     /**

  Exception trace:

  1   ReflectionMethod::__construct(Object(Tymon\JWTAuth\Commands\JWTGenerateCommand), "handle")
      /Users/Retina/userauth/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:135

  2   Illuminate\Container\BoundMethod::getCallReflector()
      /Users/Retina/userauth/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:115

  Please use the argument -v to see more details.

「JWTGenerateCommand.php」にhandle関数がないためエラーが発生しますので、以下の通りhandle関数を追加します。

vendor/tymon/jwt-auth/src/Commands/JWTGenerateCommand.php
... 中略
    public function handle() {
        $this->fire();
    }
}

再度秘密鍵の生成を試みます。

$ php artisan jwt:generate
jwt-auth secret [thQFW5fwIfpQiHSKkZfjblb0A9TP8dUP] set successfully

「config/jwt.php」ファイルに秘密鍵の設定が追加されていることを確認します。

$ grep secret config/jwt.php 
    'secret' => env('JWT_SECRET', 'thQFW5fwIfpQiHSKkZfjblb0A9TP8dUP'),

6. 認証関連のAPIの実装

ここまでに「UserController.php」で定義されたAPIはルーティング「routes/api.php」での定義も含め、全く認証の設定がなされていませんでした。そのため、以下の3点の設定を行います。

  1. 認証キー発行のAPI実装(これは認証なしでアクセス可能)
  2. ログインしているユーザの情報を返すAPI実装(要認証)
  3. 既存ユーザー情報管理APIは認証がないとアクセスができないよう設定

これらは、「UserController.php」へのAPI実装と「routes/api.php」へのルーティング設定で行います。

1) 「UserController.php」へのAPI実装

app/Http/Controllers/UserController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\User;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;

class UserController extends Controller
{
... 中略
    public function authenticate(Request $request) // emailとpasswordでアクセストークンを取得して返します
    {
        $credentials = $request->only('email', 'password');
        try {
            if (! $token = JWTAuth::attempt($credentials)) {
                return response()->json(['error' => 'invalid_credentials'], 401);
            }
        } catch (JWTException $e) {
            return response()->json(['error' => 'could_not_create_token'], 500);
        }
        $user = User::where('email', $request->email)->first();
        return response()->json(compact('user', 'token'));
    }

    public function getCurrentUser() // トークンに紐づくユーザ情報を取得して返します
    {
        $user = JWTAuth::parseToken()->authenticate();
        return response()->json(compact('user'));
    }
}

これにより、「1) 認証キー発行のAPI実装(これは認証なしでアクセス可能)」と「2) ログインしているユーザの情報を返すAPI実装(認証なし)」が実装されます。次にルーティングと認証の設定を追加します。

2) 「routes/api.php」へのルーティング設定

routes/api.php
... 中略
Route::post('authenticate','UserController@authenticate');
Route::group(['middleware' => 'jwt.auth'], function () {
  Route::resource('users', 'UserController');
  Route::get('me',  'UserController@getCurrentUser');
});

これにより、「認証キー発行のAPI」と「既存ユーザー情報管理API」に認証が必要となり、ルーティングの設定が完了します。

7. JWTAuth認証のテスト

例のごとく、「php artisan serve」を実行して、APIのテストを行います。

1) アクセストークンの取得

$ curl -X POST localhost:8000/api/authenticate -d 'email=test1@test.com' -d 'password=(uhBnji9' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   433    0   395  100    38   2392    230 --:--:-- --:--:-- --:--:--  2393
{
  "user": {
    "id": 1,
    "name": "test1",
    "email": "test1@test.com",
    "created_at": "2018-07-18 21:41:12",
    "updated_at": "2018-07-18 21:41:12"
  },
  "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMC9hcGkvYXV0aGVudGljYXRlIiwiaWF0IjoxNTMxOTg4ODg5LCJleHAiOjE1MzE5OTI0ODksIm5iZiI6MTUzMTk4ODg4OSwianRpIjoiYm5FQlBXNVBSanBEZ0FrYSJ9.Q9ytQ-sLFsg92d5GcPytIKlFJuVA55vQBaAo1LqayNo"
}

ここでいう、"token"の値がアクセストークンになります。

2) APIの実行

アクセストークンなしでAPIを実行すると「token_not_provided」と言われエラーになります。

$ curl -X GET localhost:8000/api/users | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    30    0    30    0     0    413      0 --:--:-- --:--:-- --:--:--   416
{
  "error": "token_not_provided"
}

取得したアクセストークンをセットしてAPIを実行するとうまくいきます。

以下、ユーザー情報取得するAPIの実行です。

$ curl -X GET localhost:8000/api/users  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMC9hcGkvYXV0aGVudGljYXRlIiwiaWF0IjoxNTMxOTg4ODg5LCJleHAiOjE1MzE5OTI0ODksIm5iZiI6MTUzMTk4ODg4OSwianRpIjoiYm5FQlBXNVBSanBEZ0FrYSJ9.Q9ytQ-sLFsg92d5GcPytIKlFJuVA55vQBaAo1LqayNo'| jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   449    0   449    0     0   1915      0 --:--:-- --:--:-- --:--:--  1910
{
  "current_page": 1,
  "data": [
    {
      "id": 1,
      "name": "test1",
      "email": "test1@test.com",
      "created_at": "2018-07-18 21:41:12",
      "updated_at": "2018-07-18 21:41:12"
    }
  ],
  "first_page_url": "http://localhost:8000/api/users?page=1",
  "from": 1,
  "last_page": 4,
  "last_page_url": "http://localhost:8000/api/users?page=4",
  "next_page_url": "http://localhost:8000/api/users?page=2",
  "path": "http://localhost:8000/api/users",
  "per_page": 1,
  "prev_page_url": null,
  "to": 1,
  "total": 4
}

以下、アクセストークンに対応するユーザ情報を取得するAPIの実行です。

$ curl -X GET localhost:8000/api/me  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMC9hcGkvYXV0aGVudGljYXRlIiwiaWF0IjoxNTMxOTg4ODg5LCJleHAiOjE1MzE5OTI0ODksIm5iZiI6MTUzMTk4ODg4OSwianRpIjoiYm5FQlBXNVBSanBEZ0FrYSJ9.Q9ytQ-sLFsg92d5GcPytIKlFJuVA55vQBaAo1LqayNo'| jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   127    0   127    0     0    440      0 --:--:-- --:--:-- --:--:--   440
{
  "user": {
    "id": 1,
    "name": "test1",
    "email": "test1@test.com",
    "created_at": "2018-07-18 21:41:12",
    "updated_at": "2018-07-18 21:41:12"
  }
}

以上、「10. APIへのJWTAuth認証の追加」の完了です。

次は、「11. Vue.jsとAPIベースのユーザ管理アプリへの認証の追加」です。

参考URL

参考1. JWTAuthのインストール方法 http://jwt-auth.readthedocs.io/en/develop/laravel-installation/#add-service-provider-laravel-54-or-below
参考2. 秘密鍵生成「php artisan jwt:generate」が失敗しないようにするためのJWTGenerateCommand.phpの編集 https://laracasts.com/discuss/channels/laravel/class-tymonjwtauthprovidersjwtauthserviceprovider-not-found-1

3
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?