Laravel5でJWT+Twitter OAuthの認証機能をつくる 2/3

認証機能のある、APIサーバーを作ろうとしたときにJWT（Json Web Token）という仕組みが使えそうだったので、
Laravel5で実装してみました。

[Laravel5でJWT+Twitter OAuthの認証機能をつくる 1/3](http://qiita.com/foresta/items/f770e8de906074107e57)
Laravel5でJWT+Twitter OAuthの認証機能をつくる 2/3 ← いまここ
[Laravel5でJWT+Twitter OAuthの認証機能をつくる 3/3](http://qiita.com/foresta/items/e7baeb423d0a9bdd2efb)

#### その２ということでJWTを実際につかって動作確認までを説明します。

# ルーティング
routes.phpに以下のルーティングを設定

```php
<?php

// 認証後のページ
Route::get('/authenticate', 'AuthenticateController@index');

// 認証処理を行う
Route::post('/authenticate', 'AuthenticateController@auth');

// 認証用のフォームを表示
Route::get('/authenticate/signin', 'AuthenticateController@showSignIn');
```

# Controller
ルーティングで指定した、AuthenticateControllerを作成します。

```
$ php artisan make:controller AuthenticateController
```

中身は以下のようにします。

```php:App/Http/Controllers/AuthenticateController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;

use App\Http\Requests;
use App\Http\Controllers\Controller;

class AuthenticateController extends Controller
{

    /**
     * constructor
     */
    public function __construct(){
        $this->middleware('jwt.auth', ['except' => ['showSignIn', 'auth']]);
    }


    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        // ログイン中のユーザー取得
        $loginUser = JWTAuth::parseToken()->toUser();
        return response()->json(['user' => $loginUser]);
    }


    /**
     * Show Signin form
     */
    public function showSignIn(){
        return view('authenticate.signin');
    }

    /**
     * Authenticate from email and password
     */
    public function auth(Request $request){
        //
        $credentials = $request->only('email', 'password');
        try {
            // 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
            return response()->json(['error' => 'could not create token'], 500);
        }

        return response()->json(compact('token'));
    }
}
```

Controllerでは大まかに以下の４つの処理を記述しています。

* コンストラクタ
* ログイン後のユーザー情報を表示するアクション（index）
* signin用のフォームを表示するアクション（showSignIn）
* 認証用のアクション

## コンストラクタ
まずコンストラクタでミドルウェアの指定をします。
この指定で、jwt.authを用いた認証を行えるようになります。
exceptで認証の対象外にするアクションを指定することができます。
今回はフォームの表示と認証する処理は、ログイン前でも行えるので除外します。

```php
    public function __construct(){
        $this->middleware('jwt.auth', ['except' => ['showSignIn', 'auth']]);
    }

```

## indexアクション
indexアクションは、コンストラクタでexceptされていないため、
tokenが送られていない場合は、以下のJSONが返されます。

```
{"error":"token_not_provided"}
```

indexメソッドの中ではJWTAuth::parseTokenでtokenでQueryStringで送られてきたtokenのをparseしています。
そして、toUserメソッドでUserのインスタンスを取得して、それをjsonで表示してます。
簡単ですね！

```php
    public function index()
    {
        // ログイン中のユーザー取得
        $loginUser = JWTAuth::parseToken()->toUser();
        return response()->json(['user' => $loginUser]);
    }
```

### signin用フォームの表示

SignIn用のフォームを表示するための、記載をしています。
bladeテンプレートは後述。

### 認証用のアクション
authメソッドの中では、SignInフォームから送られてきたemail, passwordが実際に存在するか、認証を行います。
```JWTAuth::attempt()```で実際に認証が行われ、正常に認証できている場合はJWTのトークンが発行されます。

```php
    /**
     * Authenticate from email and password
     */
    public function auth(Request $request){
        //
        $credentials = $request->only('email', 'password');
        try {
            // 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
            return response()->json(['error' => 'could not create token'], 500);
        }

        return response()->json(compact('token'));
    }
```

コントローラは以上です。

# View

作成するViewはsignin用のbladeテンプレートのみです。
今回は、Formヘルパーを使用します。（使用しない人は次の「Formヘルパーのインストール」は読み飛ばしてください）

## Formヘルパーのインストール
Laravel4だと標準搭載のFormヘルパーですが、Laravel5では別パッケージとなったようです。

下記サイト様を参考にインストールを行いました。
https://laravel10.wordpress.com/2015/03/08/%E5%88%9D%E3%82%81%E3%81%A6%E3%81%AElaravel-5-16-form%E3%81%AE%E4%BD%9C%E6%88%90/

まずは、Composerでインストールします。

```
$ composer require laravelcollective/html
```

そして、config/app.phpに追記します。

```php:config/app.php

  'providers'=> [
　　 // ・・・
     Collective\Html\HtmlServiceProvider::class,
  ],

  'aliases' => [
　　 // ・・・
    'Form' => Collective\Html\FormFacade::class,
    'Html' => Collective\Html\HtmlFacade::class
  ]

```

ヘルパの設定は以上です。

## SignInフォーム
SignInフォームを表示するために、以下のようなbladeテンプレートを記述します。

```php:resources/views/authenticate/signin.blade.php
{!! Form::open(array('url' => 'authenticate', 'method' => 'post')) !!}
<div class="form-group">
    {!! Form::label('email', 'メールアドレス') !!}
    {!! Form::text('email', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group">
    {!! Form::label('password', 'パスワード') !!}
    {!! Form::password('password', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group">
    {!! Form::submit('Signin', ['class' => 'btn btn-primary form-control']) !!}
</div>
{!! Form::close() !!}
```

詳しい使い方は[APIリファレンス](http://laravelcollective.com/docs/5.1/html)を参考にしてみてください。
http://laravelcollective.com/docs/5.1/html

# 動作確認
ここまできたら、実際に動作確認してみます。

以下の３点が確認できれば、とりあえずは認証機能として動作するかとおもいます。

* /authenticate にアクセスして、token_not_providedではじかれるかチェック
* /authenticate/signinでフォームにDBに登録したものを入力して、tokenが取得できるか
* 取得できたtokenをQueryStringのパラメータに入れて、/authenticateにアクセスし、ユーザー情報が取得できるか

まずはブラウザで、http://DOMAIN_NAME/authenticate にアクセスしてみます。
（DOMAIN_NAMEは適宜読み替えてください。自分の環境だと http://homestead.app のようになってます。）

![スクリーンショット 2015-08-23 0.18.19.png](https://qiita-image-store.s3.amazonaws.com/0/26081/36f72d44-a9c0-7586-2ddf-ddc540b9758a.png)

たしかに、tokenが無いよと怒られてます。

次に、/authenticate/signinにアクセスしてみます。

![スクリーンショット 2015-08-23 0.22.39.png](https://qiita-image-store.s3.amazonaws.com/0/26081/74851c2e-8763-9e10-41f1-f52e774ecdd7.png)

上のようなフォームが表示されれば成功です。
では、[その１](http://qiita.com/foresta/items/f770e8de906074107e57)で用意したユーザーの情報をいれてみます。
email: jwt-test@example.com
password: 'password'

![スクリーンショット 2015-08-23 0.28.22.png](https://qiita-image-store.s3.amazonaws.com/0/26081/582b9aa9-c702-470d-3eff-fd2ff27844cd.png)

送信すると、、、

![スクリーンショット 2015-08-23 0.28.48.png](https://qiita-image-store.s3.amazonaws.com/0/26081/b5d2984b-0ac5-ea44-9d45-2d1e4f7a9590.png)

tokenが取得できました！

このtokenをURLにくっつけて/authenticateにアクセスしてみます。

![スクリーンショット 2015-08-23 0.31.06.png](https://qiita-image-store.s3.amazonaws.com/0/26081/afe09ffc-8bb6-ca92-0a76-034d75333104.png)

ちゃんと、ユーザー情報を取得することができました。

実際に使う場合は、APIをたたく側で認証後に発行されたtokenを保持して、APIにアクセスするタイミングでtokenを一緒に送ってもらい認証する形になると思います。

以上でJWTで認証するところまでできました。

# 次回
次はTwitter OAuthでも同様に認証をしてみたいと思います。