HWIOAuthBundleを使ってSymfony2でOAuth認証を実装する

しばらくCodeceptionネタが続く予定だったのですが、Symfony2 + OAuth認証で結構はまったのでシェアしておきます。

FacebookTwitterGoogleなど、ソーシャルアカウントでログインする機能を作成したい場合、各ベンダーが提供しているAPIを利用することもできますが、HWIOAuthBundleは複数のリソースオーナーに対応しているので、こちらを利用することにしました。

基本的には本家のドキュメントを見ながら進めていきましたが、一筋縄ではいかない点などがあり、結構はまりました。
本家のドキュメント以外ではAdding HWIOAuthBundle to your Symfony2 project | /* diegocaprioli.com */が参考になると思います。

このエントリではGoogleを利用した単純なOAuth認証を組み込むまでの手順を追ってきます。

1. Symfonyプロジェクトを作成

1.1. 初期化
php composer.phar create-project symfony/framework-standard-edition Sample 2.3.3

※ AcmeDemoBundleは削除します

1.2. HWIOAuthBundleの依存関係を追加
php composer.phar require hwi/oauth-bundle 0.3.*@dev
1.3. バンドルを作成
php app/console generate:bundle

※ Vendor/SampleBundle を作成したとして以降進めていきます。

2. HWIOAuthBundleを設定

Step 1: Setting up the bundle どおりに進めればOKです

2.1. HWIOAuthBundleを有効化

app/AppKernel.php

<?php

use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = array(
            // ...
            new HWI\Bundle\OAuthBundle\HWIOAuthBundle(),
        );
    }
}
2.2. ルーティングをインポート

app/config/routing.yml

hwi_oauth_redirect:
    resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
    prefix:   /connect

3. OAuthUserProviderをService Containerに登録

  • OAuthUserProvider
  • EntityUserProvider(アプリ側にユーザー管理用のテーブルがある場合に利用)
  • FOSUBUserProvider(アプリ側のユーザー管理をFOSUserBundleで行っている場合に利用)

今回は単純なものが実現できればよいので、OAuthUserProviderを利用します。
src\Vendor\SampleBundle\Resources\config\services.ymlに以下を記述します。

parameters:
    vendor_sample.oauth_user_provider.class: HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUserProvider

services:
    vendor_sample.oauth_user_provider.service:
        class: %vendor_sample.oauth_user_provider.class%

4. リソースオーナーを設定

今回はGoogleアカウントを利用します。

4.1. Google側にアプリケーションを登録

「Redirect URIs」、「JavaScript origins」は以下のように設定しておきます。

Redirect URIs:	http://localhost:8000/login/check-google
JavaScript origins:	http://localhost:8000
4.2. リソースオーナーを設定

どおりに進めればOKです

app/config/config.yml

hwi_oauth:
    firewall_name: secured_area

    http_client:
        timeout: 10
        verify_peer: false
        ignore_errors: false
        max_redirects: 1

    resource_owners:
            google:
                type:          google
                client_id:     %google_api_client_id%
                client_secret: %google_api_client_secret%
                scope:         "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"

http_clientについて
開発環境など、SSLサーバー証明書を検証できない場合、以下のようなエラーになってしまいます。

SSL certificate problem: unable to get local issuer certificate

そのような環境ではverify_peerfalseに設定しましょう。
その他のパラメータについてはConfiguring the HTTP Clientを参照してください。

Google APIのclient_id, client_secretについて
app/config/parameters.ymlに設定した値を参照するようにしましょう。
app/config/parameters.yml.distへの追加も忘れずに。

5. セキュリティ設定

Step 3: Configuring the security layerに記述されている設定そのままではできませんでした。

5.1. security.ymlを設定

app/config/security.yml

security:
    providers:
        oauth_user_provider:
             id: vendor_sample.oauth_user_provider.service

    firewalls:
        secured_area:
            pattern: ^/
            anonymous: true
            oauth:
                resource_owners:
                    google:   "/login/check-google"
                login_path:   /login
                failure_path: /login
                oauth_user_provider:
                    service: vendor_sample.oauth_user_provider.service

    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }

ドキュメントと違う点は以下となります。

  • security直下にproviders設定が必要
  • secured_area直下にpattern, anonymous設定が必要
5.2. ルーティングを追加

app/config/routing.yml

google_login:
    pattern: /login/check-google

6. トップページ&ログインページを作成

6.1. ルーティングを追加

src/Vendor/SampleBundle/Resources/config/routing.yml

vendor_sample_homepage:
    pattern:  /
    defaults: { _controller: VendorSampleBundle:Default:index }

vendor_sample_login:
    pattern:  /login
    defaults: { _controller: VendorSampleBundle:Default:login }
6.2. アクションを追加
<?php

namespace Vendor\SampleBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction()
    {
        return $this->render('VendorSampleBundle:Default:index.html.twig');
    }

    public function loginAction()
    {
        return $this->render('VendorSampleBundle:Default:login.html.twig');
    }
}
6.3. テンプレートを作成

src\Vendor\SampleBundle\Resources\views\Default\index.html.twig

{% if app.user %}
    <h1>Hello {{ app.user.username }}!!</h1>
{% else %}
    <h1>Hello Guest!!</h1>
{% endif %}

src\Vendor\SampleBundle\Resources\views\Default\login.html.twig

<a href="{{ path('hwi_oauth_service_redirect', { 'service' : 'google' }) }}">
Login with Google
</a>
7. 確認

「Login with Google」のリンクをクリックすると、

f:id:piccagliani:20130820113035p:plain

ログインを行うと、

f:id:piccagliani:20130820113039p:plain

承認すると、トップページが表示され、Googleアカウントに設定されている名前が表示されます。


以上です。

続編として「EntityUserProvider」を使うパターンも機会を見つけて書きたいと思います。

それにしてもSymfony2に関係する日本語情報って少ないですね。。。