やりたいこと
- 表題の通り、laravel/socialiteで、twitterやfacebookのアカウント認証はできるようになったが、LINEやYahoo!JAPANのアカウントでも認証できるようにしたい。
前提
-
laravel/socialiteによる外部認証機能を使用していること
導入手順、の前に
-
毎度毎度、以下の長い手順を踏んでいくのは非常に面倒なので、これらをまとめたものをpackagistに公開して、composer requireできるようにしました。
Laravel 5.3のSocialiteに含まれていないLINEやYahoo!JAPANなどの認証サービスをcomposerを使ってサクッと実装する方法
導入手順
- 基本的に、以下の流れで実装する。
- 認証に使用するサービスのAPI仕様やらを見ながら、Providerをその仕様に合わせてガリガリ書いていけば、大体のサービスにおいては以下の手順でいける。。。と思う。
認証に使用するサービスごとにProviderを作成する。
-
LINE用プロバイダ
app/socialite/Two/LineProvider.php<?php namespace app\Socialite\Two; use Laravel\Socialite\Two\AbstractProvider; use Laravel\Socialite\Two\ProviderInterface; use Laravel\Socialite\Two\User; class LineProvider extends AbstractProvider implements ProviderInterface { protected function getAuthUrl($state) { return $this->buildAuthUrlFromBase('https://access.line.me/dialog/oauth/weblogin', $state); } protected function getTokenUrl() { return 'https://api.line.me/v1/oauth/accessToken'; } protected function getUserByToken($token) { $response = $this->getHttpClient()->get('https://api.line.me/v1/profile', [ 'headers' => [ 'X-Line-ChannelToken' => $token, ], ]); return json_decode($response->getBody(), true); } protected function mapUserToObject(array $user) { return (new User())->setRaw($user)->map([ 'id' => $user['mid'], 'name' => $user['displayName'], 'avatar' => $user['pictureUrl'], ]); } protected function getTokenFields($code) { return [ 'client_id' => $this->clientId, 'client_secret' => $this->clientSecret, 'code' => $code, 'redirect_uri' => $this->redirectUrl, 'grant_type' => 'authorization_code', ]; } }
-
Yahoo!JAPAN用プロバイダ
app/socialite/Two/YahooProvider.php<?php namespace app\Socialite\Two; use Laravel\Socialite\Two\AbstractProvider; use Laravel\Socialite\Two\ProviderInterface; use Laravel\Socialite\Two\User; use GuzzleHttp\ClientInterface; class YahooProvider extends AbstractProvider implements ProviderInterface { protected $scopeSeparator = ' '; protected $scopes = [ 'openid', 'profile', 'email', ]; protected function getAuthUrl($state) { return $this->buildAuthUrlFromBase('https://auth.login.yahoo.co.jp/yconnect/v1/authorization', $state); } protected function getTokenUrl() { return 'https://auth.login.yahoo.co.jp/yconnect/v1/token'; } protected function getUserByToken($token) { $response = $this->getHttpClient()->get('https://userinfo.yahooapis.jp/yconnect/v1/attribute?schema=openid', [ 'headers' => [ 'Authorization' => 'Bearer '.$token, ], ]); return json_decode($response->getBody(), true); } protected function mapUserToObject(array $user) { return (new User())->setRaw($user)->map([ 'id' => $user['user_id'], 'name' => $user['name'], 'email' => $user['email'], 'birth_year' => $user['birthday'], 'gender' => $user['gender'], ]); } /** * Basic認証が必要なのでOverWriteする。 * @param string $code * @return mixed */ public function getAccessTokenResponse($code) { $postKey = (version_compare(ClientInterface::VERSION, '6') === 1) ? 'form_params' : 'body'; $basic_auth_key = base64_encode($this->clientId.":".$this->clientSecret); $response = $this->getHttpClient()->post($this->getTokenUrl(), [ 'headers' => [ 'Authorization' => 'Basic '.$basic_auth_key, 'Content-Type' => 'application/x-www-form-urlencoded', ], $postKey => $this->getTokenFields($code), ]); return json_decode($response->getBody(), true); } /** * TokenFieldsに過不足があるのでOverWriteする。 * :Basic認証のため不要 * - client_id * - client_secret * :必須項目追加 * + grant_type * @param string $code * @return array */ protected function getTokenFields($code) { return [ 'code' => $code, 'redirect_uri' => $this->redirectUrl, 'grant_type' => 'authorization_code', ]; } }
SocialiteManager、SocialiteServiceProviderクラスを作成する。
-
Laravel\Socialite\SocialiteManagerクラスを継承して、作成したプロバイダを読み込むSocialiteManagerクラスを実装する
app/socialite/SocialiteManager.php<?php namespace app\Socialite; class SocialiteManager extends \Laravel\Socialite\SocialiteManager { protected function createYahooDriver() { $config = $this->app['config']['services.yahoo']; return $this->buildProvider('app\Socialite\Two\YahooProvider', $config); } protected function createLineDriver() { $config = $this->app['config']['services.line']; return $this->buildProvider('app\Socialite\Two\LineProvider', $config); } }
-
Laravel\Socialite\SocialiteServiceProviderを継承して、作成したSocialiteManagerを呼び出すためのサービスプロバイダクラスを実装する。
app/socialite/SocialiteServiceProvider.php<?php namespace app\Socialite; class SocialiteServiceProvider extends \Laravel\Socialite\SocialiteServiceProvider { public function register() { $this->app->singleton('Laravel\Socialite\Contracts\Factory', function ($app) { return new SocialiteManager($app); }); } }
設定変更
-
SocialiteServiceProviderの向き先を、上記で作成したものに変える
app/config/config.php<?php return [ // ... 'providers' => [ // ... //Laravel\Socialite\SocialiteServiceProvider::class, //除外 app\Socialite\SocialiteServiceProvider::class, //追加 // ... ], // ... ];
-
config/services.phpを編集する。
config/services.php<?php return [ // ... 'line' => [ 'client_id' => env('LINE_CLIENT_ID'), 'client_secret' => env('LINE_CLIENT_SECRET'), 'redirect' => env('LINE_REDIRECT'), ], 'yahoo' => [ 'client_id' => env('YAHOO_CLIENT_ID'), 'client_secret' => env('YAHOO_CLIENT_SECRET'), 'redirect' => env('YAHOO_REDIRECT'), ], // ... ];
-
.env.xxxxxを編集
.env.xxxxx# ... LINE_CLIENT_ID=(your-line-client-id) LINE_CLIENT_SECRET=(your-line-client-secret) LINE_REDIRECT=(your-line-redirect-url) YAHOO_CLIENT_ID=(your-yahoo-client-id) YAHOO_CLIENT_SECRET=(your-yahoo-client-secret) YAHOO_REDIRECT=(your-yahoo-redirect-url) # ...
認証実行
- あとは、Laravel 5.3で外部アカウントを使用した認証機能を実装する方法に書いたコントローラの作成以下の手順を、それぞれのプロバイダ名に読み替えて実装すれば完成。