FOSUserBundle & FOSFacebookBundleでユーザ認証


Symfony2でSNSサイトなどを作ろうと思うと必ず認証関係が必要になって、FOSUserBundle & FOSFacebookBundleでユーザ認証サイトを作ることになります。

https://github.com/FriendsOfSymfony/FOSUserBundle
https://github.com/FriendsOfSymfony/FOSFacebookBundle

しかし、このFOSUserBundle & FOSFacebookBundleで認証というのが結構クセモノでなかなかうまくベース作りができません。
OAuthを理解していてもSymfony2でのroutingやbundle内部の仕組みを理解するまでにかなりの時間がかかります。

FOSUserBundleは思った以上に簡単に実装ができます。問題はFOSFacebookBundleとの共存です。
symfony2.1での例になっています。symfony2.0ではprovider_chainなどが無くなっていますので注意してください。

一度では全部書ききれないので、まずマニュアル等には書いていないノウハウ的なことをとにかくリスト化します。あとはgithubのソースを読んでください。

1.config.ymlの基本設定

ローカルサイトなどで作成するとOAuthなどの認証が通らずエラーが出るので必ず公開ドメインでまず実験を

https://github.com/FriendsOfSymfony/FOSFacebookBundle

config.ymlとsecurity.ymlはしっかりと。

2.UserBundle, FacebookBundleは共通のログイン画面

UserBundle, FacebookBundleは共通のログイン画面(/login)になります。/loginのログイン画面のfacebookのログインボタンを押すとFacebook→OAuth→check_path: /login_check_facebookで認証の流れになります。

3._security_checkはダミーのコントローラーで処理

http://stackoverflow.com/questions/9046669/fosfacebookbundle-and-fosuserbundle

facebookBundleの_security_check(routing.yml)はpattern: /login_check_facebookなど別名にしダミーのコントローラーで処理します。 /login_checkはUserBundleで利用します。/login_check_facebookのコントローラーはダミーで大丈夫です。

4.FaceboouBundleのユーザ名は標準でfacebookId

facebookでログインしてくるユーザのユーザ名は標準ではfacebookIdになる(User modelのsetFbdataを参照)。
facebookでログインするユーザ名をfacebookのユーザ名にするにはUser modelやFacebookProvider.phpを参照

5.FacebookBundleのvalidation

FacebookとUserBundleで同一メールアドレスやユーザ名の場合はvalidationが通りません。validation.xmlを自前で準備しFacebook validation_groupsを追加する必要があります。

これにははまりました。FacebookProvider.phpの

if (count($this->validator->validate($user, 'Facebook'))) {
    // TODO: the user was found obviously, but doesnt match our expectations, do something smart
    throw new UsernameNotFoundException('The facebook user could not be stored');
}

Facebookというvalidation groupsは設定されていないのでfacebookを追加して自前で準備します。

<?xml version="1.0" ?>
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
        http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

    <class name="FOS\UserBundle\Model\User">
        <constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
            <option name="fields">usernameCanonical</option>
            <option name="errorPath">username</option>
            <option name="message">fos_user.username.already_used</option>
            <option name="groups">
                <value>Registration</value>
                <value>Profile</value>
                <value>Facebook</value>
            </option>
        </constraint>

        <constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
            <option name="fields">emailCanonical</option>
            <option name="errorPath">email</option>
            <option name="message">fos_user.email.already_used</option>
            <option name="groups">
                <value>Registration</value>
                <value>Profile</value>
                <value>Facebook</value>
            </option>
        </constraint>
    </class>

</constraint-mapping>

6.success_handler

ログインした後にロールを見てリダイレクト!などの処理はsecurity.ymlのsuccess_handlerを利用します。

Symfony/Component/Security/Http/Authentication

AuthenticationSuccessHandlerInterface onAuthenticationSuccessを実装します。
config.ymlでのinjectionも忘れずに。 RouterInterface $router,SecurityContext $securityをコンストラクタに投げているので [“@router”, “@security.context”] をconfig.ymlでインジェクトしてください。

<?php

namespace App\UserBundle\Handler;

use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Core\SecurityContext;

use Symfony\Component\Security\Core\Exception\AuthenticationException;


class AuthenticationHandler
implements AuthenticationSuccessHandlerInterface,
           AuthenticationFailureHandlerInterface
{
    
    protected $router;
    protected $security;
    
    public function __construct(RouterInterface $router,SecurityContext $security)
    {
        $this->router = $router;
        $this->security = $security;
    }
    public function onAuthenticationSuccess(Request $request, TokenInterface $token) {
        return new RedirectResponse($this->router->generate('fos_user_profile'));
    }
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception) {
        return new Response();
    }
}

あとはgithubのソースで。
https://github.com/kmusiclife/App

  • このエントリーをはてなブックマークに追加

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です