チュートリアル 中級

Laravel5でWebAPIの作成(クライアント側をAuthに変更)

前回は、クライアント側をPHPのPOST送信プログラムでデータを送信しただけでした。

今回はより実践に近くするため、Laravelのログイン認証(Auth)を実装してみます。

 

仕様

クライアント側にLaravelのログイン認証(Auth)を実装します。

LaravelのAuthを使うことで二点はまってしまったので備忘録として記述します。

ポイント

1.クライアント側のDBにもSSOのレコードをインサートする
2.パスワードは暗号化にしないとログイン認証できない

1.クライアント側のDBにもSSOのレコードをインサートする

WebAPIにあるレコードをクライアント側のDBにも同じものを入れないとログインができません。

なのでログイン認証の前にWebAPIにあるレコードをクライアントのDBにもコピーする必要が出てきます。

 

クライアント側にLaravelのAuthを実装

手順

1)Laravelをインストール
2)Authを生成
3)AuthController.php の編集
4)認証用のプログラムを移動&名前空間の変更
5)認証用プログラムの編集
  1.AuthenticatesUsersの編集
  2.SSO用のクラス新規作成
6)動作確認

 

1)Laravelをインストール

以下のページを参照

 

2)Authを生成

Laravel5.2から make:auth で認証機能を自動生成できます。

まずは認証用のデータベースの作成。

マイグレーションファイルはデフォルトで用意されています。

以下のコマンドを実行するだけです。


php artisan migrate

これで users テーブルとパスワードリセット時に利用される password_rests テーブルが生成されます。

チェックusers テーブルのパスワードは暗号化しないとログインできないので注意!
デフォルトで暗号化になっています。

make:authで自動生成。


php artisan make:auth

詳しくは以下のページを参照

 

3)AuthController.php の編集

make:auth を実行すると App\Http\Controllers\Auth\AuthController.php がコントローラーとして使われます。

このコントローラーには「ログイン認証の処理」や「新規登録の処理」が入っています。

これらはトレイトとして使われており、オリジナルはvendorディレクトリ以下にあります。

しかし、vendorディレクトリ以下のファイルは Laravel のお作法では編集が禁止されています。

なので、App\SsoAuth ディレクトリにコピーしてこれを読み込むようにします。

 
1.エイリアスを以下のように変更


# App\Http\Controllers\Auth\AuthController.php

//use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use App\SsoAuth\AuthenticatesAndRegistersUsers;

 
2.トレイトをApp\SsoAuthに移す

SsoAuth ディレクトリは新規で作成しました。

 

4)認証用のプログラムを移動&名前空間の変更

AuthenticatesAndRegistersUsersの名前空間を変更


# App\SsoAuth\AuthenticatesAndRegistersUsers

//namespace Illuminate\Foundation\Auth;
namespace App\SsoAuth;
:

AuthenticatesUsers の名前空間を変更


# App\SsoAuth\AuthenticatesUsers

//namespace Illuminate\Foundation\Auth;
namespace App\SsoAuth;
:

同様に、「RegistersUsers.php」や「RedirectsUsers.php」も変更しておきます。

 

5)認証用プログラムの編集

1.AuthenticatesUsersの編集

ログイン処理の前にWebAPI(SSO)に接続して該当レコードがあるか検証します。

loginメソッドの本体はAuthenticatsUsersにあるのでこのファイルを編集します。


# App\SsoAuth\AuthenticatesUsers

// ログインメソッドの本体
public function login(Request $request)
{
// バリデーション
$this->validateLogin($request);

// スロットル取得
$throttles = $this->isUsingThrottlesLoginsTrait();

// もし、規定の回数を超えていたら
if ($throttles && $lockedOut = $this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);

return $this->sendLockoutResponse($request);
}

// 認証情報取得
$credentials = $this->getCredentials($request);

// SSOサーバーからデータを取ってくる (この箇所を追加)
if(!\App\Services\SSO::pre_login($request->email, $request->password)){
return $this->sendFailedLoginResponse($request); //ログイン認証失敗処理
}

// 認証
if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) {
return $this->handleUserWasAuthenticated($request, $throttles); //ログイン認証成功処理
}

// 失敗だったらスロットルをカウントアップ
if ($throttles && ! $lockedOut) {
$this->incrementLoginAttempts($request);
}

return $this->sendFailedLoginResponse($request);
}


 
2.SSO用のクラス新規作成

SSO用のクラスを App\Services に SSO.php を新規作成。

このクラスに、WebAPIに接続して該当レコードがあるかないかを検証するスクリプトを書きます。


# App\Services\SSO.php

class SSO
{
public static function pre_login($id, $pass){

// 送信データ
$data = array(
"email" => $id,
"password" => $pass
);

// デバッグ出力
Log::debug('id="'.$id.'"');
Log::debug('pass="'.$pass.'"');

// JSON形式に変換
$data = json_encode($data);

// ストリームコンテキストのオプションを作成
$options = array(
// HTTPコンテキストオプションをセット
'http' => array(
'method'=> 'POST',
'header'=> 'Content-type: application/json; charset=UTF-8', //JSON形式で表示
'content' => $data
)
);

// ストリームコンテキストの作成
$context = stream_context_create($options);

// POST送信
$url = 'http://localhost/ssoapi/public/login';
$raw_data = file_get_contents($url, false, $context);

// デバッグ出力
Log::debug($raw_data);

// jsonからstdClassに変換
$data = json_decode($raw_data);
Log::debug('result="'.$data->result.'"');
Log::debug('name="'.$data->name.'"');
Log::debug('email="'.$data->email.'"');
Log::debug('password="'.$data->password.'"');

// SSOにレコードあり
if($data->result){
// クライアント側にレコードがあるか確認
$user = User::where('email',$data->email)->first();

// デバッグ出力
Log::debug('$user="'.$user.'"');
if($user){
// クライアント側にレコードがある
self::copy_to_user($data,$user);
$user->save();
return true;
}else{
// クライアント側にレコードがない(初めてのログイン)
$newuser = new User;
self::copy_to_user($data,$newuser);
$newuser->save();
return true;
}
}else{
// SSOにレコードなし(エラー)
return false;
}
}

// コピー用関数
private static function copy_to_user($result,$user)
{
$user->name = $result->name;
$user->email = $result->email;
$user->password = bcrypt($result->password);
}


}

 

6)動作確認

1.クライアント側のログイン画面にアクセス

クライアント側には何もレコードがなく、SSO側にレコードがあるケースとします。

クライアント側のDB

WebAPI(SSO)側のDB

2.SSOで登録されているレコードでログイン

ログイン情報を入力し、POST送信すると

1.JSONでWebAPIにアクセス

2.該当レコードがあるか検証

3.該当レコードがあればJSONでリターン

4.クライアント側で該当レコードをインサート

5.ログイン処理

となります。

3.マイページ(認証済み画面)

クライアント側のDBを確認してみます。

WebAPIにあったレコードがクライアント側にも挿入されているのが確認できました。

ちなみにデバッグ用で出力したログファイルは以下のような感じになります。

App\storage\logs\laravel-2018-07-03.log を確認。

以上です。

本庄マサノリ

仕事でLaravelを使っています。気づいたことや新しい発見など情報を発信していきます。メールはこちら

 

-チュートリアル, 中級