LaravelでSSOのAPIを作成(クライアント側)

2019/07/19

「LaravelでSSOのAPIを作成する」シリーズの第三回です。

前前回、Laravelの make:auth 認証機能を自動生成しました。

今回はこの認証機能をカスタマイズします。DB の照合処理を API にさせるように記述します。

 

手順
はまったところ

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

 

1)環境設定ファイルにAPIのアドレスを設定

環境設定ファイルにSSOのAPIのアドレスを記述します。

file_get_contents関数でURLを指定するときに使います。

.env

:
SSO_URL=http://localhost/practice_sso/public/login

 

\config\app.php

:
'ssoURL' => env('SSO_URL'),

 

2)認証用トレイトを App\SsoAuth に移す

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

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

しかし、実態ファイルはトレイトとして格納されており、オリジナルはvendorディレクトリ以下 ( vendor\laravel\frameworks\src\Illuminate\Foundation\Auth\ ) にあります。

vendorディレクトリ以下のファイルは Git の管理外です。また Laravel のお作法としてもこのVendorディレクトリ以下のファイルを触るのは NG です。

なので、App 直下に SsoAuthディレクトリを作成し、このディレクトリ以下にVendor以下に置いてあったAuth関連のファイルを設置します。

 

3)名前空間を変更

App\Http\Controllers\Auth\AuthController.php

//use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers; // ← こっちをやめて
use App\SsoAuth\AuthenticatesAndRegistersUsers; // ← こっちにする

 

App\SsoAuth\AuthenticateAndRegistersUsers.php

//namespace Illuminate\Foundation\Auth; // ← こっちをやめて
namespace App\SsoAuth; // ← こっちにする

trait AuthenticatesAndRegistersUsers
{
    use AuthenticatesUsers, RegistersUsers {
        AuthenticatesUsers::redirectPath insteadof RegistersUsers;
        AuthenticatesUsers::getGuard insteadof RegistersUsers;
    }
}

 

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

トレイトを追っていくとloginメソッドの本体は AuthenticatsUsers.php だとわかります。

このファイルを編集します。

コメントアウトで記述している「SSOサーバーからデータを取ってくる」以外はそのままです。

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);
        }

         // SSOサーバーからデータを取ってくる
        if(!\App\Services\SSO::pre_login($request->email,$request->password)){
            return $this->sendFailedLoginResponse($request);
        }

        // 認証情報取得
        $credentials = $this->getCredentials($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);
    }

 

5)SSO用のクラスを新規作成

SSO用のクラスを App\Services に 新規に作成します。

このクラスに、SSOのAPIに接続するスクリプトを書きます。


# App\Services\SSO.php

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

        // 送信データ
        $data = array(
            "id" => $id,
            "password" => $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送信
        $ssoURL = \Config::get('app.ssoURL');
        $raw_data = @file_get_contents($ssoURL, false, $context);

        // jsonからstdClassに変換
        $data = json_decode($raw_data);

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

 
以上です。

 

PHPフレームワーク Laravel入門

僕がはじめてLaravelを学習するために参考にしたサイトは、掌田津耶乃(しょうだつやの)さんの libro というサイトです。当時(2016年)、Laravel学習サイトの中でもこのサイトは群を抜いてわかりやすく説明されていたので、とても勉強になったのを覚えています。この本は掌田津耶乃が書いた本なので、わかりやすく解説されているだろうと kindle で購入しました。2019年7月の時点でいうと日本国内にて唯一の Laravel の良書と言っても良いかと思います。しかし、かなりわかりやすく解説されているとはいえ、PHP中級者以上のスキルは必要です。PHP自体の知識が乏しい方は独習PHP 第3版をあわせて購入することをお勧めします。

Amazonで詳細を見る

オススメ

 

本庄マサノリ

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

 

-チュートリアル, 上級