認証機能のある、APIサーバーを作ろうとしたときにJWT(Json Web Token)という仕組みが使えそうだったので、
Laravel5で実装してみました。
Laravel5でJWT+Twitter OAuthの認証機能をつくる 1/3
Laravel5でJWT+Twitter OAuthの認証機能をつくる 2/3 ← いまここ
Laravel5でJWT+Twitter OAuthの認証機能をつくる 3/3
その2ということでJWTを実際につかって動作確認までを説明します。
ルーティング
routes.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
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では大まかに以下の4つの処理を記述しています。
- コンストラクタ
- ログイン後のユーザー情報を表示するアクション(index)
- signin用のフォームを表示するアクション(showSignIn)
- 認証用のアクション
コンストラクタ
まずコンストラクタでミドルウェアの指定をします。
この指定で、jwt.authを用いた認証を行えるようになります。
exceptで認証の対象外にするアクションを指定することができます。
今回はフォームの表示と認証する処理は、ログイン前でも行えるので除外します。
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で表示してます。
簡単ですね!
public function index()
{
// ログイン中のユーザー取得
$loginUser = JWTAuth::parseToken()->toUser();
return response()->json(['user' => $loginUser]);
}
signin用フォームの表示
SignIn用のフォームを表示するための、記載をしています。
bladeテンプレートは後述。
認証用のアクション
authメソッドの中では、SignInフォームから送られてきたemail, passwordが実際に存在するか、認証を行います。
JWTAuth::attempt()
で実際に認証が行われ、正常に認証できている場合はJWTのトークンが発行されます。
/**
* 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に追記します。
'providers'=> [
// ・・・
Collective\Html\HtmlServiceProvider::class,
],
'aliases' => [
// ・・・
'Form' => Collective\Html\FormFacade::class,
'Html' => Collective\Html\HtmlFacade::class
]
ヘルパの設定は以上です。
SignInフォーム
SignInフォームを表示するために、以下のようなbladeテンプレートを記述します。
{!! 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
動作確認
ここまできたら、実際に動作確認してみます。
以下の3点が確認できれば、とりあえずは認証機能として動作するかとおもいます。
- /authenticate にアクセスして、token_not_providedではじかれるかチェック
- /authenticate/signinでフォームにDBに登録したものを入力して、tokenが取得できるか
- 取得できたtokenをQueryStringのパラメータに入れて、/authenticateにアクセスし、ユーザー情報が取得できるか
まずはブラウザで、http://DOMAIN_NAME/authenticate にアクセスしてみます。
(DOMAIN_NAMEは適宜読み替えてください。自分の環境だと http://homestead.app のようになってます。)
たしかに、tokenが無いよと怒られてます。
次に、/authenticate/signinにアクセスしてみます。
上のようなフォームが表示されれば成功です。
では、その1で用意したユーザーの情報をいれてみます。
email: jwt-test@example.com
password: 'password'
送信すると、、、
tokenが取得できました!
このtokenをURLにくっつけて/authenticateにアクセスしてみます。
ちゃんと、ユーザー情報を取得することができました。
実際に使う場合は、APIをたたく側で認証後に発行されたtokenを保持して、APIにアクセスするタイミングでtokenを一緒に送ってもらい認証する形になると思います。
以上でJWTで認証するところまでできました。
次回
次はTwitter OAuthでも同様に認証をしてみたいと思います。