将Facebook Connect与Symfony2中的HWIOAuthBundle绑定

时间:2014-05-09 13:38:19

标签: php symfony hwioauthbundle

我已经从少数几个来源阅读了文档和示例,但仍无法获得此HWIOAuthBundle的工作原理。我使用用户ID和密码登录表单,在管理部分手动添加已经正常工作的用户ID和密码。

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

我的安全:

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 }

学生实体:

<?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;

应用程序/配置/ 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

应用程序/配置/ 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" }

我的控制器:

<?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.twig:

<!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和访问令牌并保存到数据库中(用于绑定Facebook)
  2. 如何在数据库中查找Facebook ID。如果存在,请在我的Controller中为ROLE_USER提供正常的loginAction。如果不存在则抛出异常。
  3. 如果这个Bundle不能解决我的问题,是否有更适合我需要的Bundle或功能?

2 个答案:

答案 0 :(得分:4)

您需要创建自己的提供程序,该提供程序实现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

在文档中阅读更多内容:How to Create a custom User Provider

答案 1 :(得分:0)

看看帮助我连接到FB的this,您可以使用FB的响应在DB中保存您想要的任何内容,对于您的模板,我将此代码用于我的注册表单:

<script>
    window.fbAsyncInit = function() {
        // init the FB JS SDK
        FB.init({
            appId      : 'XXXX',                        // App ID from the app dashboard
            //channelUrl : '//yourdomain.com/channel.html',      // Channel file for x-domain comms
            status     : true,                                 // Check Facebook Login status
            xfbml      : true                                  // Look for social plugins on the page
        });
    };

    // Load the SDK asynchronously
    // This javascript must be after body html tag
    /*(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/all.js";
        fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));*/

    function fb_login() {

        FB.getLoginStatus(function(response) {
            if (response.status === 'connected') {
                // connected
                //alert('Already connected, redirect to login page to create token.');
                document.location = "{{ url("hwi_oauth_service_redirect", {service: "facebook"}) }}";
            } else {
                // not_authorized
                FB.login(function(response) {
                    if (response.authResponse) {
                        document.location = "{{ url("hwi_oauth_service_redirect", {service: "facebook"}) }}";
                    } else {
                        //alert('Cancelled.');
                    }
                }, {display: 'popup', scope: 'email'});
            }
        });
    }

</script>

<p>
    <div class="fb-login-button" scope="email" registration-url="{{ path("hwi_oauth_service_redirect", {service: "facebook"}) }}" data-width="200">Registrarse con Facebook</div>
</p>

<form class="form_theme" action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST">
    {{ form_widget(form) }}
    <div class="submit center">
        <input type="submit" value="{{ 'registration.submit'|trans({}, 'FOSUserBundle') }}" />
    </div>
</form>