LaravelでOAuthを利用してTwitter、Facebook、Googleアカウントでログインを実装


投稿日:2015年1月9日
  • 16
  • 2
  • 33



「OAuth wrapper for Laravel 4」を利用してOAuthを実装

laravel_oauth

情報流出のニュースが世間を騒がせている昨今、ログイン機構をOAuthに限定するWebサービスも増えてきました。

セキュリティ対策の難しさを考えれば、小さなWebサービスが取る戦略としては妥当なものかもしれません。

私の作成した「GOいけん(ゴーイケン)」もOAuthに限定しようかと考えたのですが「タブーに縛られない意見を投稿する」という目的から考えて、SNSアカウントを使いたくないという方もいるかと思い、通常のログイン機構も残しました。


目次

OAuth wrapper for Laravel 4の導入方法
Facebookアプリの設定
新規登録用のコントローラーを作成
ログイン用のコントローラーを作成
TwitterアカウントでもOAuthを利用できるようにする
GoogleアカウントでもOAuthを利用できるようにする


OAuth wrapper for Laravel 4の導入方法

githubの「OAuth wrapper for Laravel 4ページ」にありますが、導入は至って簡単です。

今回はWindowsのローカルにXAMPPを構築し、インストールしたLaravelにOAuth wrapper for Laravel 4を導入します。

1.まずはLaravelのルートディレクトにある「composer.json」追加

前後に項目がある場合は最後の「,(カンマ)」を忘れずに。

"require": {
	//(省略)
	"artdarek/oauth-4-laravel": "dev-master",
}

2.composerでアップデート

コマンドプロンプトでコンポーサーの場所を指定してアップデートを行います。

>cd C:\xampp\htdocs\xampp\example\
>composer update

(省略)
  - Installing artdarek/oauth-4-laravel (dev-master 12d27a1)
    Downloading: 100%

Writing lock file
Generating autoload files
Generating optimized class loader

3.オートロードサービスプロバイダーとクラスエイリアスに追加

app/config/app.php」を開きオートロードサービスプロバイダーの項目「‘providers’ => array(…」の最後に追加します。

'Artdarek\OAuth\OAuthServiceProvider',

クラスエイリアス「‘aliases’ => array(」の項目にも追加。

'OAuth'          	=> 'Artdarek\OAuth\Facade\OAuth',

4.OAuth wrapper for Laravel 4の設定ファイルを作成

artisanコマンドで作成する方法が用意されているので、ありがたく利用させていただきます。
コマンドプロンプトにて。

>php artisan config:publish artdarek/oauth-4-laravel

これで「app/config/packages/artdarek/oauth-4-laravel/config.php」が作成されます。

デフォルトでは以下の様なFacebook用の雛形が用意されています。

        'Facebook' => array(
            'client_id'     => '',
            'client_secret' => '',
            'scope'         => array(),
        ),

Facebookアプリの設定

続いて各アプリケーションを作成して、クライアントIDなどを取得します。(Laravelの設定より、これを探すほうがずっと大変でしたw)

FacebookのAll Appsページ」へアクセス。

1.新しくFacebookアプリを作成

Add a New App」ボタンをクリック。

laravel_oauth01

2.Facebookアプリの設定

Settings > Basic > App Domains」で「example.com」「localhost.example.com」を追加。さらにアプリを動作させるにはメールアドレスも入力する必要があります

laravel_oauth02

ローカル環境でFacebookのOAuthを利用する方法は「過去の投稿」でまとめたので必要な方は参照してください。

これで設定は完了ですが、AdvancedタブClient OAuth Loginの項目がONになっていることを確認してください。

laravel_oauth03

再び「Settings > Basic」に戻り「App ID」と「App Secret」を「app/config/packages/artdarek/oauth-4-laravel/config.php」の「client_id」と「client_secret」に追加します。

laravel_oauth13

(App SecretはShowボタンをクリックすれば表示されます)

        'Facebook' => array(
            'client_id'     => '0000000000000000',
            'client_secret' => '00000000000000000000000000000000',
            'scope'         => array(),
        ),

scopeに値を入力すると、Facebookから取得できるリソースを拡張することができます。
詳しくはFacebookの「Permissions with Facebook Login」を参照してください。

scopeに何も入力せずに取得できる値は「public_profile (Default)」の項目です。
今回はメールアドレスを取得したいので「email」を追加します。(複数指定する場合はカンマ区切りで入力してください。)

            'scope'         => array(email),

これで準備は完了です。


新規登録用のコントローラーを作成

コントローラーの仕様はサイトによって異なるので合わせて記述してください。
GOいけん」ではレストフルコントローラーを採用しているので「app/controllers/RegisterController.php」にfacebookページを作成します。

雛形は「OAuth wrapper for Laravel 4」のUsage examplesにあります。

雛形を簡単に解説すると、$fb->getAuthorizationUri()でURLを作成してcodeを取得したら再びリダイレクトしてtokenを取得、その値を使ってユーザー情報を取得するという流れになっています。

そのままコピーして「dd($result);」の部分を「var_dump($result);」として書き出すと、以下の値が取れます。

array(11) {
  ["id"]=>
  string(15) "000000000000000"
  ["email"]=>
  string(19) "hoge@example.com"
  ["first_name"]=>
  string(7) "hoge"
  ["gender"]=>
  string(4) "male"
  ["last_name"]=>
  string(5) "huga"
  ["link"]=>
  string(60) "https://www.facebook.com/app_scoped_user_id/000000000000000/"
  ["locale"]=>
  string(5) "ja_JP"
  ["name"]=>
  string(14) "hoge  huga"
  ["timezone"]=>
  int(9)
  ["updated_time"]=>
  string(24) "2013-07-25T06:54:03+0000"
  ["verified"]=>
  bool(true)
}

ちゃんとscopeに指定したemailの情報も取得できてますね。
後はこれらの値を使って好きに調理します。今回はEloquent ORMでデータベースへ書き込んでみました。

public function getFacebook()
{
    // get data from input
    $code = Input::get( 'code' );

    // get fb service
    $fb = OAuth::consumer( 'Facebook' );

    // check if code is valid

    // if code is provided get user data and sign in
    if ( !empty( $code ) ) {

        // This was a callback request from facebook, get the token
        $token = $fb->requestAccessToken( $code );

        // Send a request with it
        $result = json_decode( $fb->request( '/me' ), true );

		// バリデーションでチェックするには連想配列にする必要あり
		$oa_id = array('oa_id' => $result['id']);

		// バリデーションルールの指定
		// usersテーブルのoa_flagsがfacebookの行でoa_idが一意かをチェック
		$rules = array(
			'oa_id' => 'unique:users,oa_id,NULL,id,oa_flags,facebook',
		);

		// バリデーションメッセージの指定
		$messages = array(
			'unique' => 'このユーザーは既に登録されています。', // カスタムメッセージ(オリジナルだと変数名が表示されるので)
		);

		// バリデーションチェック
		$validator = Validator::make($oa_id, $rules, $messages);

		// バリデーションNGなら
		if($validator->fails())
		{
			return Redirect::to('register')->withInput()->withErrors($validator);
		}

		// Eloquent ORMで$userインスタンスを作成してデータベースへ書き込む
		$user = new User;
		$user->oa_flags = "facebook"; // フラグのセット
		$user->oa_id = $result['id']; // サービスごとに一意の値をセット
		$user->oa_email = $result['email']; // サービスで利用しているメールアドレスをセット
		$user->save();

		// ログインしてID取得してリダイレクトする
		Auth::login($user);

		$id = Auth::user()->id;
	    return Redirect::to('user/'.$id);
    }

    // 一番最初にアクセスした時
    else {
        // get fb authorization
        $url = $fb->getAuthorizationUri();

        // return to facebook login url
         return Redirect::to( (string)$url );
    }
}

OAuthで複数のSNSアカウントを利用する場合、ユーザーの一意性を確保するには何のサービスを使ってログインしているかと、サービス内で一意のIDをセットにしておく必要があります。

今回はusersテーブルoa_flagsoa_idというカラムを追加して管理することにしました。
そして、その値を使って登録済みかどうかのバリデーションをしています。

ログインに成功したら「user/<id>」ページヘリダイレクトします。

これで「/register/facebook」にアクセスすればFacebookのユーザー情報を利用して、ユーザー登録することができるようになりました。


ログイン用のコントローラーを作成

登録ができたのでログインも全く同じように実装します。
登録とログインが同じボタンの例も多いですが、ログインページのボタンをクリックすると登録されるというのも、なんかモヤモヤするので、今回はログインページを「login/facebook」に分けました。

app/controllers/LoginController.php」に追加します。

public function getFacebook()
{
    // get data from input
    $code = Input::get( 'code' );

    // get fb service
    $fb = OAuth::consumer( 'Facebook' );

    // check if code is valid

    // if code is provided get user data and sign in
    if ( !empty( $code ) ) {

        // This was a callback request from facebook, get the token
        $token = $fb->requestAccessToken( $code );

        // Send a request with it
        $result = json_decode( $fb->request( '/me' ), true );

		$user = User::where('oa_flags', "facebook")->where('oa_id', $result['id'])->first();

		// 登録されていない場合は別処理
		if ( !empty( $user ) ) { // 登録されている場合
			if (Auth::loginUsingId($user->id)) {
				// ログインしたらユーザーページヘリダイレクト
				$id = Auth::user()->id;
				return Redirect::to('user/'.$id);
			}
		} else { // 登録されていない場合はリダイレクトでエラー表示
			$message = '<p class="vali_error">ご指定のユーザーは、まだ登録されていません。</p>';
			return Redirect::to('login')->withErrors([$message]);
		}
    }
    // if not ask for permission first
    else {
        // get fb authorization
        $url = $fb->getAuthorizationUri();

        // return to facebook login url
         return Redirect::to( (string)$url );
    }
}

先ほど作成した「oa_flags」と「oa_id」を使ってユーザー情報を取得。
$result[‘id’]が取得できている時点で正当なFacebookユーザーであることは確認済みなので、確認とログインが同時にできるAuth::attempt()ではなく、Auth::loginUsingId()でログインします。

ログインしたら登録時と同じようにユーザーページヘリダイレクトします。

以上でFacebookのユーザー情報を利用して新規登録とログインをする仕組みができました。


TwitterアカウントでもOAuthを利用できるようにする

tokenの取得方法などは多少異なるのでライブラリのサンプルを参照してください。
しかし基本的な考え方は同じです。

client_idclient_secretの取得ページがわからず手間取ったのでメモがてら残しておきます。

1.アプリケーションを作成するアカウントで携帯電話を登録する

アプリケーションの作成するユーザーは携帯電話の登録が必須になったので「設定 > モバイル」で登録します。

laravel_oauth05

携帯番号を入力するとコードが送られてくるので認証を行います。

ちなにみ認証用のコードが記載されたメールは海外から届くため、迷惑メール設定に注意してください。「迷惑メールの問題」でだいぶ時間を無駄にしました。

2.新しくTwitterアプリを作成

Twitter Application Management」へアクセスして「Create New App」をクリック。

laravel_oauth04

3.Twitterアプリの設定をする

Name:」にアプリ名、
Description:」に説明
Website:」にURL
Callback URL:」に同じURL

Yes, I agreeにチェックして「Create」ボタンクリック

laravel_oauth06

4.client_idとclient_secretに対応する値を取得

登録が完了したらKeys and Access TokensタブにあるConsumer Key (API Key)client_idConsumer Secret (API Secret)client_secretにそれぞれ対応します。

laravel_oauth07

Facebookの時と同じように「app/config/packages/artdarek/oauth-4-laravel/config.php」にTwitter用の設定を追加します。

'Twitter' => array(
	'client_id'     => '0000000000000000000000000',
	'client_secret' => '00000000000000000000000000000000000000000000000000',
	// No scope - oauth1 doesn't need scope
),

これでコントローラーを作成すれば、TwitterのOAuthも使えるようになります。

補足、var_dumpで取れる$resultの値

解説にありますがTwitterはoauth1なので規格的にscopeがありません。

下記の$resultの出力を見ればわかる通り、メールアドレスは提供されないため、どうしても必要なら追加でメールアドレスの入力を求めるページに飛ばす必要があります。
認証を行うという本来の目的には使えますが、メールアドレスを渡さないというのは納得がいきませんね。(自分はアプリの登録に携帯の番号を強要するくせにw)

array(42) {
  ["id"]=&gt;
  float(000000000000)
  ["id_str"]=&gt;
  string(10) "000000000000"
  ["name"]=&gt;
  string(11) "hoge"
  ["screen_name"]=&gt;
  string(10) "example.com"
  ["location"]=&gt;
  string(0) ""
  ["profile_location"]=&gt;
  NULL
  ["description"]=&gt;
  string(197) "000000000000000000000000"
  ["url"]=&gt;
  string(22) "http://t.co/0000000000"
  ["entities"]=&gt;
  array(2) {
    ["url"]=&gt;
    array(1) {
      ["urls"]=&gt;
      array(1) {
        [0]=&gt;
        array(4) {
          ["url"]=&gt;
          string(22) "http://t.co/00000000"
          ["expanded_url"]=&gt;
          string(19) "http://example.com"
          ["display_url"]=&gt;
          string(11) "example.com"
          ["indices"]=&gt;
          array(2) {
            [0]=&gt;
            int(0)
            [1]=&gt;
            int(22)
          }
        }
      }
    }
    ["description"]=&gt;
    array(1) {
      ["urls"]=&gt;
      array(0) {
      }
    }
  }
  ["protected"]=&gt;
  bool(false)
  ["followers_count"]=&gt;
  int(324)
  ["friends_count"]=&gt;
  int(371)
  ["listed_count"]=&gt;
  int(0)
  ["created_at"]=&gt;
  string(30) "Wed Dec 24 11:13:19 +0000 2014"
  ["favourites_count"]=&gt;
  int(0)
  ["utc_offset"]=&gt;
  NULL
  ["time_zone"]=&gt;
  NULL
  ["geo_enabled"]=&gt;
  bool(false)
  ["verified"]=&gt;
  bool(false)
  ["statuses_count"]=&gt;
  int(5)
  ["lang"]=&gt;
  string(2) "ja"
  ["status"]=&gt;
  array(22) {
    ["created_at"]=&gt;
    string(30) "Thu Jan 01 05:46:03 +0000 2015"
    ["id"]=&gt;
    float(0000000000000)
    ["id_str"]=&gt;
    string(18) "0000000000000"
    ["text"]=&gt;
    string(74) "0000000000000"
    ["source"]=&gt;
    string(66) "

GoogleアカウントでもOAuthを利用できるようにする

こちらも同じくメモがてら残します。

1.Googleアプリを作成

ログインして「Applications Overview」へアクセス。
Create Application」ボタンをクリックしてアプリケーションを作成。

laravel_oauth08

1.Googleアプリの設定

Application Identifier:」にアプリ名、
Application Title:」に解説、
Authentication Options (Advanced):」は「Open to all Google Accounts users (default)」を選択。
Create Application」ボタンクリック。

laravel_oauth09

Google Developers Console」へアクセスして左のMENUから「APIと認証」にある「認証情報」をクリック。
続いて「クライアントIDを作成」をクリック。

laravel_oauth10
アプリケーションの種類 ウェブ アプリケーション
承認済みの JAVASCRIPT 生成元 http://example.com/
http://localhost.example.com/
(あとで設定するのも面倒なので、ローカル用と本番用の2つを予め登録しておきます。)
承認済みのリダイレクト URI http://example.com/login/google
http://example.com/register/google
http://localhost.example.com/login/google
http://localhost.example.com/register/google
(Googleの場合は認証後にリダイレクトするURLをきっちり最後まで指定しないとダメみたいです。)

続いて左のメニューから「認証画面」をクリックして表示されたウィンドウにそれぞれの項目を入力。

メールアドレス hoge@example.com
サービス名 hoge
ホームページの URL (省略可) http://example.com/
サービス ロゴ (省略可) http://example.com/image/google-api-120×120.png
(120×120で画像必要みたい)
GOOGLE+ ページ (省略可) 000000000000000000000

以上で「保存」ボタンをクリック。

3.client_idとclient_secretに対応する値を取得

クライアント IDclient_idクライアント シークレットclient_secretに対応しています。

laravel_oauth12

上2つと同じように「app/config/packages/artdarek/oauth-4-laravel/config.php」に追記

'Google' => array(
    'client_id'     => '0000000000000000000000000000000000000000000mh.apps.googleusercontent.com',
    'client_secret' => '000000000000000000000',
    'scope'         => array('userinfo_email', 'userinfo_profile'),
), 

scopeはuserinfo_emailメールアドレスuserinfo_profileID情報を取得しています。
openid profile email」なんかがあるようです。

詳しくは「OpenID Connect (OAuth 2.0 for Login) – Google Accounts Authentication and Authorization — Google Developers」を参照してください。

これでGoogleのアカウントでもOAuthが利用できるようになりました。

補足、var_dumpで取れる$resultの値

array(10) {
  ["id"]=&gt;
  string(21) "000000000000000000"
  ["email"]=&gt;
  string(19) "hoge@example.com"
  ["verified_email"]=&gt;
  bool(true)
  ["name"]=&gt;
  string(12) "hogehuga"
  ["given_name"]=&gt;
  string(6) "huga"
  ["family_name"]=&gt;
  string(6) "hoge"
  ["link"]=&gt;
  string(45) "https://plus.google.com/000000000000000000"
  ["picture"]=&gt;
  string(92) "https://lh5.googleusercontent.com/-VHq8AnIX40U/AAAAAAAAAAI/AAAAAAAAAEM/9-Of1GZvNPg/photo.jpg"
  ["gender"]=&gt;
  string(4) "male"
  ["locale"]=&gt;
  string(2) "ja"
}

以上で、TwitterFacebookGoogleのアカウントから新規登録・ログインができるようになりました。

実際のサンプルは「GOいけん」の「新規登録ページ」や「ログインページ」をご覧ください。

laravel_oauth14


現在のページを共有する



現在のページに関連する記事


おすすめの記事


いただいたコメントなど

  1. yoshi のコメント:

    Facebookアプリの設定について質問させてください。

    私自身、一般ユーザーがFacebookログインができるよう、自身のWEBサービスに実装したいと思っています。
    Developersの「Status & Review」項目の「Items in Review」より、Facebookに申請しての通過認証は不要なのでしょうか。

    • oxy のコメント:

      説明不足で失礼しました。
      Developersの「Status & Review」項目の「Status」タブの「Do you want to make this app and all its live features available to the general public?」と書かれた項目は「YES」にしておく必要があります。
      「Items in Review」タブの項目は設定しなくても動作します。

      しかし各サービスのアプリ作成画面は、作成するごとにコロコロ変わるので迷いやすいですね。

  2. yoshi のコメント:

    早速のご返答、ありがとうございます!
    publicをYESにすれば、アクセスしたユーザはログイン可能になりますね。Items in Reviewは、ユーザの一般情報以上を入手したいときにFacebookになぜその情報が必要なのか、申請しなくてはいけないのですね。

    • oxy のコメント:

      なるほど、そんな登録が必要だったんですね。
      毎回メールアドレスくらいしか取得してなかったので知りませんでした。
      情報ありがとうございました。

  3. すいません のコメント:

    ・どのページにアクセスしても常にログイン認証済みかどうかの判定はどうしておりますでしょうか?セッションにFacebookのIDを保存させてそれがあるかないかだけの判定は危険でしょうか?
    ・ログアウトさせたいときはどうすればよいでしょうか??

    • oxy のコメント:

      ログイン済みかの判定はセッションではなく、ControllerでAuth::check()をフラグにifで分岐すればできます。
      ログアウトはログアウト用のControllerでAuth::logout()としてください。

      大変ありがたいことにLaravelは最新のドキュメントが日本語化されているので、ぜひ利用しましょう。
      認証 5.1 Laravel

コメントを残す

コメントは認証制のため、すぐには反映されません。

プログラミングに関する質問は「日本語でプログラミングの悩みを解決するQ&Aサイト sukegra」をご利用ください。