绑定Facebook连接与HWIOAuthBundle在Symfony2


Binding Facebook Connect with HWIOAuthBundle in Symfony2

我已经从几个来源阅读文档和例子,但仍然不能得到这个HWIOAuthBundle的作品。我已经登录表单使用用户ID和密码手动添加在管理部分,已经工作得很好。

我想在他们成功登录后在用户区添加绑定Facebook按钮,这样他们就可以在将来使用正常的ID/密码登录Facebook。我搜索过这个HWIOAuthBundle,但找不到任何类似的情况。

My Security:

security:
    encoders:
        Sifo'UserBundle'Entity'Student: plaintext
    providers:
        user_area:
            entity: { class: SifoUserBundle:Student, property: code }
    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false
            anonymous: true
        login:
            pattern:  ^/user/login$
            security: false
    user_area:
        pattern: ^/user
        anonymous: false
        provider: user_area
        form_login: 
            check_path: /user/login_check
            login_path: /user/login
        logout:
            path:   /user/logout
            target: /user
    user_area_socials:
        anonymous: false
        oauth:
            resource_owners:
                facebook:  "/login/check-facebook"
            login_path:    /login
            use_forward:   false
            failure_path:  /login
            oauth_user_provider:
                service: hwi_oauth.user.provider.entity

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

Student Entity:

<?php
namespace Sifo'UserBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
use Symfony'Component'Security'Core'User'UserInterface;
/**
 * Student
 */
class Student implements UserInterface, 'Serializable
{
    /**
     * @var integer
     */
    private $id;
    /**
     * @var string
     */
    private $email;
    /**
     * @var string
     */
    private $code;
    /**
     * @var string
     */
    private $facebookId;
    /**
     * @var string
     */
    private $facebookAccessToken;

app/config/routing.yml

hwi_oauth_redirect:
    resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
    prefix:   /user
hwi_oauth_login:
    resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
    prefix:   /login
facebook_login:
    pattern: /login/check-facebook

app/config/config.yml

hwi_oauth:
    # name of the firewall in which this bundle is active, this setting MUST be set
    firewall_name: user_area_socials
    resource_owners:
        facebook:
            type:                facebook
            client_id:           XXXXX73105XXXXX
            client_secret:       XXXXX5534ce8d0c50893fbb9c45XXXXX
            scope:               "email"
services:
    hwi_oauth.user.provider.entity:
        class: HWI'Bundle'OAuthBundle'Security'Core'User'OAuthUserProvider

登录表单(Login .html.twig):

  <form class="form-signin" action="{{ path('user_login_check') }}" method="post">
    <h2 class="form-signin-heading">sign in now</h2>
    <div class="login-wrap">
        <input type="text" class="form-control" placeholder="User ID" autofocus id="username" name="_username" />
        <input type="password" class="form-control" placeholder="Password" id="password" name="_password" />
        <label class="checkbox">
            <input type="checkbox" value="remember-me"> Remember me
            <span class="pull-right">
                <a href="{{ path('public_default') }}"><i class="icon-home"></i> Back to home</a>
            </span>
        </label>
        <button class="btn btn-lg btn-login btn-block" type="submit">Sign in</button>
        <p>or you can sign in via social network</p>
        <div class="login-social-link">
            <a href="{{ path('user_facebook_login') }}" class="facebook">
                <i class="icon-facebook"></i>
                Facebook
            </a>
            <a href="{{ path('user_twitter_login') }}" class="twitter">
                <i class="icon-twitter"></i>
                Twitter
            </a>
        </div>         
    </div>
  </form>

user_facebook_login路由:

user_facebook_login:
    pattern:  /login_facebook
    defaults: { _controller: "SifoUserBundle:Default:facebook" }

My Controller:

<?php
namespace Sifo'UserBundle'Controller;
use Symfony'Component'HttpFoundation'Request;
use Symfony'Bundle'FrameworkBundle'Controller'Controller;
use Symfony'Component'Security'Core'SecurityContext;
use Symfony'Component'Security'Core'Exception'AccessDeniedException;
use Sifo'UserBundle'Form'DefaultType;
class DefaultController extends Controller
{    
    public function facebookAction()
    {
        return $this->render('SifoUserBundle:Default:facebook.html.twig');
    }
    public function loginAction()
    {
        $request = $this->getRequest();
        $session = $request->getSession();
        // get the login error if there is one
        if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
            $error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
        } else {
            $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
            $session->remove(SecurityContext::AUTHENTICATION_ERROR);
        }
        return $this->render('SifoUserBundle:Default:login.html.twig', array(
            // last username entered by the user
            'last_username' => $session->get(SecurityContext::LAST_USERNAME),
            'error'         => $error,
        ));
    }
}

facebook.html。枝:

<!DOCTYPE html>
<html lang="en">
<head>
</head>
  <body class="login-body">
<script>
  // This is called with the results from from FB.getLoginStatus().
  function statusChangeCallback(response) {
    console.log('statusChangeCallback');
    console.log(response);
    // The response object is returned with a status field that lets the
    // app know the current login status of the person.
    // Full docs on the response object can be found in the documentation
    // for FB.getLoginStatus().
    if (response.status === 'connected') {
        // connected
        document.location = "{{ url("hwi_oauth_service_redirect", {service: "facebook"}) }}";
    } else if (response.status === 'not_authorized') {
        // not_authorized
        FB.login(function(response) {
            if (response.authResponse) {
                document.location = "{{ url("hwi_oauth_service_redirect", {service: "facebook"}) }}";
            } else {
                alert('Cancelled.');
            }
        }, {scope: 'email'});
    } else {
      // The person is not logged into Facebook, so we're not sure if
      // they are logged into this app or not.
      document.getElementById('status').innerHTML = 'Please log ' +
        'into Facebook.';
    }
  }
  // This function is called when someone finishes with the Login
  // Button.  See the onlogin handler attached to it in the sample
  // code below.
  function checkLoginState() {
    FB.getLoginStatus(function(response) {
      statusChangeCallback(response);
    });
  }
  window.fbAsyncInit = function() {
  FB.init({
    appId      : 'XXXXX73105XXXXX',
    cookie     : true,  // enable cookies to allow the server to access 
                        // the session
    xfbml      : true,  // parse social plugins on this page
    version    : 'v2.0' // use version 2.0
  });
  // Now that we've initialized the JavaScript SDK, we call 
  // FB.getLoginStatus().  This function gets the state of the
  // person visiting this page and can return one of three states to
  // the callback you provide.  They can be:
  //
  // 1. Logged into your app ('connected')
  // 2. Logged into Facebook, but not your app ('not_authorized')
  // 3. Not logged into Facebook and can't tell if they are logged into
  //    your app or not.
  //
  // These three cases are handled in the callback function.
  FB.getLoginStatus(function(response) {
    statusChangeCallback(response);
  });
  };
  // Load the SDK asynchronously
  (function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return;
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/en_US/sdk.js";
    fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));
  // Here we run a very simple test of the Graph API after login is
  // successful.  See statusChangeCallback() for when this call is made.
  function testAPI() {
    console.log('Welcome!  Fetching your information.... ');
    FB.api('/me', function(response) {
      console.log('Successful login for: ' + response.name);
      document.getElementById('status').innerHTML =
        'Thanks for logging in, ' + response.name + '!';
    });
  }
</script>
  </body>
</html>
  1. 如何获取Facebook ID和Access token并保存到数据库中(用于绑定Facebook)
  2. 如何在数据库中检查Facebook ID。如果存在,在我的控制器中像正常的loginAction一样给出ROLE_USER。如果不存在则抛出异常。
  3. 如果这个Bundle不能解决我的问题,是否有更好的Bundle或功能适合我的需求?

您需要创建自己的提供程序,它实现OAuthAwareUserProviderInterface。在loadUserByOAuthUserResponse方法从$response参数,你可以得到任何关于facebook用户的信息。例子:

class MyOAuthProvider implements UserProviderInterface, OAuthAwareUserProviderInterface
{
    public function loadUserByOAuthUserResponse(UserResponseInterface $response)
    {
        $token = $response->getAccessToken();
        $facebookId =  $response->getUsername(); // Facebook ID, e.g. 537091253102004
        $username = $response->getRealName();
        $email = $response->getEmail();
        // search user in database
        $result = $this->em->getRepository('AppUserBundle:User')->findOneBy(
            array(
                'facebookId' => $facebookId
            )
        );
        if(!$result) {
            $user = new User();
            $user->setEmail($email);
            $user->setUsername($username);
            $user->setFacebookId($facebookId);
            // ..
            // save to database instructions
            // ..
        }
        return $this->loadUserByUsername($username);
    }
    // other methods
}

别忘了在app/config/config.yml

中指定你的自定义提供商
services:
    app.user.provider:
        class: App'UserBundle'Entity'MyOAuthProvider

app/config/security.yml

firewalls:
        ...
        user_area_socials:
            oauth:
                oauth_user_provider:
                    service: app.user.provider

在文档中阅读更多:如何创建自定义用户提供商