LaravelのPHPで、かなりハマってしまった問題。
目次
Laravelでソーシャルログインの認証拒否のテスト
Laravelでソーシャル認証を実装しました。
LaravelのControllerでコールバック内では、以下の通りに実装しました。
1 2 3 4 5 |
try { $user = Socialite::driver('twitter')->user(); } catch (Exception $e) { return redirect("/"); } |
これで、Exceptionが発生してもcatchしてリダイレクトされるはずです。
早速実験してみます。
ソーシャルログイン時に以下の記事出てくる画面が表示された場合、Twitter、Facebook、Googleでログインを拒否したとします。
すると、それぞれ次のエラーが発生します。
Twitterで拒否した場合
Twitterで拒否してみます。
・https://(url)/auth/login/callback/twitter?denied=xxxxx
InvalidArgumentException in TwitterProvider.php line 15:Invalid request. Missing OAuth verifier.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
in TwitterProvider.php line 15 at TwitterProvider->user() in SocialController.php line 35 at SocialController->getTwitterAuthCallback() at call_user_func_array(array(object(SocialController), 'getTwitterAuthCallback'), array()) in Controller.php line 256 at Controller->callAction('getTwitterAuthCallback', array()) in ControllerDispatcher.php line 164 at ControllerDispatcher->call(object(SocialController), object(Route), 'getTwitterAuthCallback') in ControllerDispatcher.php line 112 at ControllerDispatcher->Illuminate\Routing\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103 at Pipeline->then(object(Closure)) in ControllerDispatcher.php line 114 at ControllerDispatcher->callWithinStack(object(SocialController), object(Route), object(Request), 'getTwitterAuthCallback') in ControllerDispatcher.php line 69 at ControllerDispatcher->dispatch(object(Route), object(Request), 'App\Http\Controllers\Auth\SocialController', 'getTwitterAuthCallback') in Route.php line 203 at Route->runWithCustomDispatcher(object(Request)) in Route.php line 134 at Route->run(object(Request)) in Router.php line 708 at Router->Illuminate\Routing\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103 at Pipeline->then(object(Closure)) in Router.php line 710 at Router->runRouteWithinStack(object(Route), object(Request)) in Router.php line 675 at Router->dispatchToRoute(object(Request)) in Router.php line 635 at Router->dispatch(object(Request)) in Kernel.php line 236 at Kernel->Illuminate\Foundation\Http\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in VerifyCsrfToken.php line 50 at VerifyCsrfToken->handle(object(Request), object(Closure)) at call_user_func_array(array(object(VerifyCsrfToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in ShareErrorsFromSession.php line 49 at ShareErrorsFromSession->handle(object(Request), object(Closure)) at call_user_func_array(array(object(ShareErrorsFromSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in StartSession.php line 62 at StartSession->handle(object(Request), object(Closure)) at call_user_func_array(array(object(StartSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in AddQueuedCookiesToResponse.php line 37 at AddQueuedCookiesToResponse->handle(object(Request), object(Closure)) at call_user_func_array(array(object(AddQueuedCookiesToResponse), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in EncryptCookies.php line 59 at EncryptCookies->handle(object(Request), object(Closure)) at call_user_func_array(array(object(EncryptCookies), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in CheckForMaintenanceMode.php line 44 at CheckForMaintenanceMode->handle(object(Request), object(Closure)) at call_user_func_array(array(object(CheckForMaintenanceMode), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103 at Pipeline->then(object(Closure)) in Kernel.php line 122 at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 87 at Kernel->handle(object(Request)) in index.php line 54 |
Facebookで拒否した場合
Facebookで拒否してみます。
・https://(url)/auth/login/callback/facebook?error=access_denied&error_code=200&error_description=Permissions+error
ClientException in RequestException.php line 107:Client error:
GET https://graph.facebook.com/oauth/access_token?client_id=ccc&client_secret=ddd&redirect_uri=(url)
resulted in a400 Bad Request
response:
{"error":{"message":"Missing authorization code","type":"OAuthException","code":1,"fbtrace_id":"xxx"}}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
in RequestException.php line 107 at RequestException::create(object(Request), object(Response)) in Middleware.php line 65 at Middleware::GuzzleHttp\{closure}(object(Response)) in Promise.php line 201 at Promise::callHandler('1', object(Response), array(object(Promise), object(Closure), null)) in Promise.php line 154 at Promise::GuzzleHttp\Promise\{closure}() in TaskQueue.php line 61 at TaskQueue->run(true) in Promise.php line 242 at Promise->invokeWaitFn() in Promise.php line 219 at Promise->waitIfPending() in Promise.php line 262 at Promise->invokeWaitList() in Promise.php line 221 at Promise->waitIfPending() in Promise.php line 62 at Promise->wait() in Client.php line 129 at Client->request('get', 'https://graph.facebook.com/oauth/access_token', array('query' => array('client_id' => 'ccc', 'client_secret' => 'ddd', 'code' => null, 'redirect_uri' => 'https://(url)/auth/login/callback/facebook'))) in Client.php line 87 at Client->__call('get', array('https://graph.facebook.com/oauth/access_token', array('query' => array('client_id' => 'ccc', 'client_secret' => 'ddd', 'code' => null, 'redirect_uri' => 'https://(url)/auth/login/callback/facebook')))) in FacebookProvider.php line 75 at Client->get('https://graph.facebook.com/oauth/access_token', array('query' => array('client_id' => 'ccc', 'client_secret' => 'ddd', 'code' => null, 'redirect_uri' => 'https://(url)/auth/login/callback/facebook'))) in FacebookProvider.php line 75 at FacebookProvider->getAccessToken(null) in AbstractProvider.php line 195 at AbstractProvider->user() in SocialController.php line 74 at SocialController->getFacebookAuthCallback() at call_user_func_array(array(object(SocialController), 'getFacebookAuthCallback'), array()) in Controller.php line 256 at Controller->callAction('getFacebookAuthCallback', array()) in ControllerDispatcher.php line 164 at ControllerDispatcher->call(object(SocialController), object(Route), 'getFacebookAuthCallback') in ControllerDispatcher.php line 112 at ControllerDispatcher->Illuminate\Routing\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103 at Pipeline->then(object(Closure)) in ControllerDispatcher.php line 114 at ControllerDispatcher->callWithinStack(object(SocialController), object(Route), object(Request), 'getFacebookAuthCallback') in ControllerDispatcher.php line 69 at ControllerDispatcher->dispatch(object(Route), object(Request), 'App\Http\Controllers\Auth\SocialController', 'getFacebookAuthCallback') in Route.php line 203 at Route->runWithCustomDispatcher(object(Request)) in Route.php line 134 at Route->run(object(Request)) in Router.php line 708 at Router->Illuminate\Routing\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103 at Pipeline->then(object(Closure)) in Router.php line 710 at Router->runRouteWithinStack(object(Route), object(Request)) in Router.php line 675 at Router->dispatchToRoute(object(Request)) in Router.php line 635 at Router->dispatch(object(Request)) in Kernel.php line 236 at Kernel->Illuminate\Foundation\Http\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in VerifyCsrfToken.php line 50 at VerifyCsrfToken->handle(object(Request), object(Closure)) at call_user_func_array(array(object(VerifyCsrfToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in ShareErrorsFromSession.php line 49 at ShareErrorsFromSession->handle(object(Request), object(Closure)) at call_user_func_array(array(object(ShareErrorsFromSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in StartSession.php line 62 at StartSession->handle(object(Request), object(Closure)) at call_user_func_array(array(object(StartSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in AddQueuedCookiesToResponse.php line 37 at AddQueuedCookiesToResponse->handle(object(Request), object(Closure)) at call_user_func_array(array(object(AddQueuedCookiesToResponse), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in EncryptCookies.php line 59 at EncryptCookies->handle(object(Request), object(Closure)) at call_user_func_array(array(object(EncryptCookies), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in CheckForMaintenanceMode.php line 44 at CheckForMaintenanceMode->handle(object(Request), object(Closure)) at call_user_func_array(array(object(CheckForMaintenanceMode), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103 at Pipeline->then(object(Closure)) in Kernel.php line 122 at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 87 at Kernel->handle(object(Request)) in index.php line 54 |
Googleで拒否した場合
Googleで拒否してみます。
・https://(url)/auth/login/callback/google?error=access_denied
ClientException in RequestException.php line 107:Client error:
POST https://accounts.google.com/o/oauth2/token
resulted in a400 Bad Request
response:
{
"error" : "invalid_request",
"error_description" : "Missing required parameter: code"
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
in RequestException.php line 107 at RequestException::create(object(Request), object(Response)) in Middleware.php line 65 at Middleware::GuzzleHttp\{closure}(object(Response)) in Promise.php line 201 at Promise::callHandler('1', object(Response), array(object(Promise), object(Closure), null)) in Promise.php line 154 at Promise::GuzzleHttp\Promise\{closure}() in TaskQueue.php line 61 at TaskQueue->run(true) in Promise.php line 242 at Promise->invokeWaitFn() in Promise.php line 219 at Promise->waitIfPending() in Promise.php line 262 at Promise->invokeWaitList() in Promise.php line 221 at Promise->waitIfPending() in Promise.php line 62 at Promise->wait() in Client.php line 129 at Client->request('post', 'https://accounts.google.com/o/oauth2/token', array('form_params' => array('client_id' => 'eee', 'client_secret' => 'fff', 'code' => null, 'redirect_uri' => 'https://(url)/auth/login/callback/google', 'grant_type' => 'authorization_code'))) in Client.php line 87 at Client->__call('post', array('https://accounts.google.com/o/oauth2/token', array('form_params' => array('client_id' => 'eee', 'client_secret' => 'fff', 'code' => null, 'redirect_uri' => 'https://(url)/auth/login/callback/google', 'grant_type' => 'authorization_code')))) in GoogleProvider.php line 55 at Client->post('https://accounts.google.com/o/oauth2/token', array('form_params' => array('client_id' => 'eee', 'client_secret' => 'fff', 'code' => null, 'redirect_uri' => 'https://(url)/auth/login/callback/google', 'grant_type' => 'authorization_code'))) in GoogleProvider.php line 55 at GoogleProvider->getAccessToken(null) in AbstractProvider.php line 195 at AbstractProvider->user() in SocialController.php line 111 at SocialController->getGoogleAuthCallback() at call_user_func_array(array(object(SocialController), 'getGoogleAuthCallback'), array()) in Controller.php line 256 at Controller->callAction('getGoogleAuthCallback', array()) in ControllerDispatcher.php line 164 at ControllerDispatcher->call(object(SocialController), object(Route), 'getGoogleAuthCallback') in ControllerDispatcher.php line 112 at ControllerDispatcher->Illuminate\Routing\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103 at Pipeline->then(object(Closure)) in ControllerDispatcher.php line 114 at ControllerDispatcher->callWithinStack(object(SocialController), object(Route), object(Request), 'getGoogleAuthCallback') in ControllerDispatcher.php line 69 at ControllerDispatcher->dispatch(object(Route), object(Request), 'App\Http\Controllers\Auth\SocialController', 'getGoogleAuthCallback') in Route.php line 203 at Route->runWithCustomDispatcher(object(Request)) in Route.php line 134 at Route->run(object(Request)) in Router.php line 708 at Router->Illuminate\Routing\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103 at Pipeline->then(object(Closure)) in Router.php line 710 at Router->runRouteWithinStack(object(Route), object(Request)) in Router.php line 675 at Router->dispatchToRoute(object(Request)) in Router.php line 635 at Router->dispatch(object(Request)) in Kernel.php line 236 at Kernel->Illuminate\Foundation\Http\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in VerifyCsrfToken.php line 50 at VerifyCsrfToken->handle(object(Request), object(Closure)) at call_user_func_array(array(object(VerifyCsrfToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in ShareErrorsFromSession.php line 49 at ShareErrorsFromSession->handle(object(Request), object(Closure)) at call_user_func_array(array(object(ShareErrorsFromSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in StartSession.php line 62 at StartSession->handle(object(Request), object(Closure)) at call_user_func_array(array(object(StartSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in AddQueuedCookiesToResponse.php line 37 at AddQueuedCookiesToResponse->handle(object(Request), object(Closure)) at call_user_func_array(array(object(AddQueuedCookiesToResponse), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in EncryptCookies.php line 59 at EncryptCookies->handle(object(Request), object(Closure)) at call_user_func_array(array(object(EncryptCookies), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in CheckForMaintenanceMode.php line 44 at CheckForMaintenanceMode->handle(object(Request), object(Closure)) at call_user_func_array(array(object(CheckForMaintenanceMode), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124 at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103 at Pipeline->then(object(Closure)) in Kernel.php line 122 at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 87 at Kernel->handle(object(Request)) in index.php line 54 |
これ、全部、以下の関数の呼び出し元でExceptionが発生しています。
$user = Socialite::driver('twitter')->user();
ちゃんとTry~CatchでExceptionをCatchしているのに何で????
PHPでネームスペース内で例外をキャッチするときは、グローバルスペースにエスケープしないとダメ
調べてみるとちゃんと書いてありました。
When catching an exception inside a namespace it is important that you escape to the global space:
私の不勉強で、PHPの仕様としては初歩的な考え方で、ミスっていました。
以下のようにしてしまうと、Exceptionでcatch出来るのは、同じネームスペース内のExceptionのみになってしまいます。
Socialite::driver内でのExceptionはcatch出来ません。
1 2 3 4 5 |
try { $user = Socialite::driver('twitter')->user(); } catch (Exception $e) { return redirect("/"); } |
Socialite::driver内のExceptionをcatchするには、以下のように、Exception ではなくて、バックスラッシュを付けてグローバルな名前空間であることを示して、\Exception をcatchする必要があります。
1 2 3 4 5 |
try { $user = Socialite::driver('twitter')->user(); } catch (\Exception $e) { return redirect("/"); } |
これでOKです。
まとめ
Exceptionのグローバルなnamespaceの考え方は、C#にもJavaにも存在しない概念のはずです。
私のようにJava、C#出身のPHPプログラマーは勘違いしてしまいます。
PHPの文法は以下の本で勉強し直します。
どれか一冊という人には以下の「PHP+MySQLマスターブック」をおすすめします。
最後まで読んでいただきありがとうござました。
この記事が気に入っていただけたらシェアしてくれると嬉しいです。
コメント