简体   繁体   English

在Symfony2中将Facebook Connect与HWIOAuthBundle绑定

[英]Binding Facebook Connect with HWIOAuthBundle in Symfony2

I've read documentations and examples from few sources but still can't get this HWIOAuthBundle works. 我已经从几个来源阅读了文档和示例,但仍然无法使HWIOAuthBundle正常工作。 I've login form using user ID and password which added manually in Admin section that already works fine. 我已经使用用户ID和密码登录了表单,该用户ID和密码已在“管理”部分手动添加,并且已经可以正常使用。

I want to add Binding Facebook Button in User Area after they login successfully, so they can login with normal ID/Password either Facebook Login in future. 他们成功登录后,我想在用户区域中添加“绑定Facebook按钮”,以便他们将来可以使用普通ID /密码登录或通过Facebook登录。 I've searching about this HWIOAuthBundle but can't find any similar case like this. 我正在搜索此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 应用程序/配置/ 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 应用程序/配置/ 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 Form (login.html.twig) : 登录表单(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>

Routing for user_facebook_login : 路由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.twig : 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. How to get Facebook ID and Access token and saved into database (for binding Facebook) 如何获取Facebook ID和访问令牌并保存到数据库中(用于绑定Facebook)
  2. How to check in database for Facebook ID. 如何在数据库中检查Facebook ID。 If Exist, give ROLE_USER like normal loginAction in my Controller. 如果存在,则在我的控制器中给ROLE_USER像普通的loginAction一样。 If not exist throw exception. 如果不存在,则抛出异常。
  3. If this Bundle can't accommodate my problems, is there any better Bundle or function which fit for my needs? 如果此Bundle无法解决我的问题,是否有适合我需求的更好的Bundle或功能?

You need to create your own provider, which implements OAuthAwareUserProviderInterface . 您需要创建自己的提供程序,该提供程序实现OAuthAwareUserProviderInterface In loadUserByOAuthUserResponse method from $response parameter you can get any info about Facebook-user. $response参数的loadUserByOAuthUserResponse方法中,您可以获得有关Facebook用户的任何信息。 Example: 例:

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
}

Don't forget specify your custom provider in app/config/config.yml 不要忘记在app / config / config.yml中指定您的自定义提供程序

services:
    app.user.provider:
        class: App\UserBundle\Entity\MyOAuthProvider

and in app/config/security.yml 并在app / config / security.yml中

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

Read more in docs: How to Create a custom User Provider 在文档中阅读更多信息: 如何创建自定义用户提供程序

Take a look this that helped me to connect to FB, you can save whatever you want in the DB using the response from FB, for your template, I use this code for my registration form: 看一下有助于我连接到FB,您可以使用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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM