Laravel Socialite の独自ドライバを実装する
この記事は Laravelリファレンス発売記念!販売促進!! Advent Calendar 2015 - Adventar の3日目の記事です。
ちょうど1年前にこんな記事を書きました。
ドライバの独自実装
今書いています。ごめんなさい。更新したら通知するようにしますのでストックしてくれていいのよ?(チラチラ http://qiita.com/localdisk/items/2e2724f31864fd49b675
気がついたら一年経ってたよ…。というわけでドライバの実装をしてみたいと思います。現在 Socialite で実装されているドライバは
となります。一年前と比較すると LinkedIn と BItbucket が増えましたね。今回は折角なので はてなのOAuth ドライバを実装したいと思います。自分はてなーなので。
はてなの OAuth のバージョン
調べてみるとはてなの OAuth のバージョンは1のようです。Socialite だと一緒なのは Twitter と Bitbucket ですね。ソースコードを読んでみると2つクラスを作る必要があるようです。
- Provider
- Socialite のユーザーインターフェース
- Server
- OAuth 周りを担当
ですね。まずは、app/Socialite
ディレクトリを作成しましょう。
HatenaProvider
空でOK。
<?php namespace App\Socialite; use Laravel\Socialite\One\AbstractProvider; class HatenaProvider extends AbstractProvider { }
親クラスの Laravel\Socialite\One\AbstractProvider
ですが、abstract class なのに abstract method がない(困惑)のでこれでよいです。
HatenaServer
<?php namespace App\Socialite; use Laravel\Socialite\One\User; use League\OAuth1\Client\Server\Server; use League\OAuth1\Client\Credentials\TokenCredentials; class HatenaServer extends Server { /** * {@inheritDoc} */ public function urlTemporaryCredentials() { $scopes = implode(',', config('services.hatena.scope')); return "https://www.hatena.com/oauth/initiate?scope={$scopes}"; } /** * {@inheritDoc} */ public function urlAuthorization() { return 'https://www.hatena.ne.jp/oauth/authorize'; } /** * {@inheritDoc} */ public function urlTokenCredentials() { return 'https://www.hatena.com/oauth/token'; } /** * {@inheritDoc} */ public function urlUserDetails() { return 'http://n.hatena.com/applications/my.json'; } /** * {@inheritDoc} */ public function userDetails($data, TokenCredentials $tokenCredentials) { $user = new User(); $user->uid = $data['url_name']; $user->nickname = $data['display_name']; $user->name = $data['url_name']; $user->imageUrl = $data['profile_image_url']; $user->email = ''; $used = ['url_name', 'display_name', 'profile_image_url']; foreach ($data as $key => $value) { if (strpos($key, 'url') !== false) { if (!in_array($key, $used)) { $used[] = $key; } $user->urls[$key] = $value; } } // Save all extra data $user->extra = array_diff_key($data, array_flip($used)); return $user; } /** * {@inheritDoc} */ public function userUid($data, TokenCredentials $tokenCredentials) { return $data['url_name']; } /** * {@inheritDoc} */ public function userEmail($data, TokenCredentials $tokenCredentials) { return; } /** * {@inheritDoc} */ public function userScreenName($data, TokenCredentials $tokenCredentials) { return $data['name']; } }
各メソッドの説明
urlTemporaryCredentials
Request token の取得。はてなの場合、ここが特殊で scope
というパラメータ名で "承認を求める操作名" を渡す必要があります(複数の場合はカンマ区切りで渡す)。
- read_public
- write_public
- read_private
- write_private
この情報を渡すために今回は config/services.php
に"承認を求める操作名"を定義しています。
<?php return [ 'hatena' => [ 'client_id' => 'XXX', 'client_secret' => 'XXX', 'redirect' => 'http://localhost:8000/hatena/login', 'scope' => ['read_public', 'write_public'] ], ];
urlAuthorization
リダイレクトする認証用URLを返します。はてなの場合は PC / スマホ / 携帯電話 用にそれぞれ違うURLが用意されているので真面目に作る場合はデバイス判定が必要です。
urlTokenCredentials
Access token を取得するURLを返します。
urlUserDetails
ユーザー情報を取得するURLを返します。
userDetails
ユーザー取得APIを叩いた結果をオブジェクトに詰めています。
userUid / userEmail / userScreenName
継承元のメソッドはこれらのメソッドをコールした時に通信してるので、そうしないようにオーバーライドしています。Socialite の実装を参考に書いただけはあんまり深い意味はないです。
AuthServiceProvider に登録
独自ドライバを実装したら使えるように登録します。AuthServiceProvider
の boot
メソッドにこんな感じで。
<?php class AuthServiceProvider extends ServiceProvider public function boot(GateContract $gate) { $this->registerPolicies($gate); \Socialite::extend('hatena', function($app) { $setting = $app['config']['services.hatena']; $config = array_merge([ 'identifier' => $setting['client_id'], 'secret' => $setting['client_secret'], 'callback_uri' => $setting['redirect'], ], $setting); return new HatenaProvider($app['request'], new HatenaServer($config)); }); } }
使ってみる。
<?php // routes.php // view にはこんな感じで書く // <p><a href="{{ url('github/ahthorize') }}">github login</a></p> // <p><a href="{{ url('hatena/ahthorize') }}">hatena login</a></p> Route::get('{provider}/ahthorize', function ($provider) { return Socialite::with($provider)->redirect(); }); Route::get('{provider}/login', function ($provider) { /** @var \Laravel\Socialite\Contracts\User $data */ $data = Socialite::with($provider)->user(); dd($data); });
シンプル!
参考
Consumer key を取得して OAuth 開発をはじめよう - Hatena Developer Center
宣伝
よろしくおねがいします!