3

我已经构建了一个非常简单的 CakePHP 应用程序来测试 Facebook PHP SDK 的可能实现,用户可以使用该应用程序或 Facebook 进行注册,也可以使用该应用程序或 Facebook 登录。但是因为用户可以在应用程序上做事,所以即使他们通过 Facebook 帐户登录/注册,他们也会在应用程序上拥有一个用户帐户。

到目前为止,我已经创建了两种处理身份验证和获取用户信息的方法:

// Asks user to authenticate
public function facebook()
{
    $params = array(
      'redirect_uri' => 'http://domain.com/users/signupfacebook',
      'scope'=> 'email',
      'display' => 'popup'
    );

    $loginUrl = $this->Facebook->Sdk->getLoginUrl($params);

    // Need to know if user is already a user on OUR app
    // If true log them in. If false redirect to signup form like below

    $this->autoRender = false;
    $this->response->header('Location', $loginUrl);

}

// Handle the return
public function signupfacebook()
{
    $user = $this->Facebook->Sdk->getUser();

    if($user)
    {
        try
        {
            $facebookuser = $this->Facebook->Sdk->api('/me');

            $this->set('facebookuser', $facebookuser);
        }
        catch(FacebookApiException $e)
        {
            error_log($e);
            $user = NULL;
        }
   }
   else
   {
        $this->Session->setFlash('An error has occurred! Please try again.');

        $this->redirect(array('action'=>'index'));
   }
}

因此,一个用户说我想使用 Facebook 进行身份验证,这使用了我的控制器的 facebook() 方法,然后它会询问他们的许可并根据此操作重定向他们。目前它只会将他们发送到一个注册页面,其中一些字段是根据他们传递的用户信息预先填写的,如下所示:

<?php echo $this->Form->create('User'); ?>

    <?php echo $this->Form->input('User.email', array('type' => 'text', 'default'=> $facebookuser['email'], 'label' => array('class' => 'placeholder', 'text' => 'Email address') )); ?>

        <?php echo $this->Form->input('User.firstname', array('type' => 'text', 'default'=> $facebookuser['first_name'], 'label' => array('class' => 'placeholder', 'text' => 'Firstname') )); ?>

        <?php echo $this->Form->input('User.lastname', array('type' => 'text', 'default'=> $facebookuser['last_name'], 'label' => array('class' => 'placeholder', 'text' => 'Lastname') )); ?>

        <?php echo $this->Form->input('User.username', array('type' => 'text', 'default'=> $facebookuser['username'], 'label' => array('class' => 'placeholder', 'text' => 'Username') )); ?>

        <?php echo $this->Form->input('User.password', array('value' => '','type' => 'password', 'label' => array('class' => 'placeholder', 'text' => 'Password') )); ?>

    <button type="submit">Create</button>

<?php echo $this->Form->end(); ?>

但我这里有几个问题:

问题 1.)如果用户已经在系统中拥有一个带有他们刚刚输入的 Facebook 凭据的帐户,那么它需要处理这个问题并让用户登录。这是否需要使用 Facebook 端的任何特殊功能?因为我只想在用户表中搜索匹配的帐户,然后自动登录,但我没有在网上找到任何在 FB 身份验证发生后验证您自己的用户表的示例。

问题 2.)可能与上一个问题有关,但是当用户注册帐户时,不会保存与他们用于登录的 Facebook 帐户的关联,因此如果当他们尝试使用 Facebook 再次登录时,将不会看到关联,除非我在数据库中搜索类似的详细信息,但这似乎很不稳定,而且 API 的使用不正确。本质上,用户只是使用 FB 来填充表单,而实际上并未使用他们的 Facebook 帐户进行实际注册。

我可以检查数据库中是否存在与通过 Facebook 传递的电子邮件地址相同的电子邮件地址,但如果他们从那以后更改了它怎么办?我考虑过可能将 Facebook 用户 ID 存储在应用程序中的用户 ID 表中,以便存储连接。这会是一个解决方案吗?或者错误的方法来做到这一点?

例如一个新表来存储 FB 用户和 CakePHP 应用程序用户之间的链接:

id
user_id (this is the relationship to your USER table)
facebook_user_id

但即使这样做,我也不确定如何利用它以有用的方式正确链接帐户并正确处理通过 Facebook 的身份验证,而不是仅在某些详细信息匹配时自动填充表单或登录用户(我确信这有潜在的安全风险)。

问题 3.)当用户通过 Facebook 发送回注册表单时,他们会收到以下 URL(出于安全原因,注意位已更改):

http://domain.com/users/signupfacebook?state=dbf2f6dds322b7cb90d71b6c958a001bf4a3ba&code=AQa7-GDsesM0ZfgswjgGF-mMKwjcoboLl19WKprIA2-f4iZzUdsd8o8z-NweYYODzySS3h9GksBw0G9WCXj79Pp-0ldyeIRCOLSt9gfgfsmEFEfOrEO6gm7a0jmDuQvchdsaHaw1QpI8RdGTCrqAPlLzpHGcqiCtBvXjiQtBhQP--tMr8CIlvRwbrJRwiZwF6xo30howlRkVTLddsdDCDt60_KGznPVmEe-T4Qbu9gdkv9v#_=_

据我所知:https ://developers.facebook.com/docs/howtos/login/server-side-login/我应该在上面发布的两种方法之间创建一个额外的步骤来处理代码并获得一个访问令牌回来。

但是我已经访问了填写注册表单所需的所有信息,而无需执行 OAuth 流程的第二阶段并获得访问令牌!所以不确定在这种情况下我是否需要它......或者我需要它吗?如果是这样,它将如何帮助解决前两个问题?

4

3 回答 3

2

以下是允许用户通过 注册的步骤facebook

我用来完成此任务的表结构如下,

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(200) NOT NULL,
  `email` varchar(255) NOT NULL,
  `password` varchar(200) NOT NULL,
  `profile_name` varchar(100) NOT NULL,
  `dob` date NOT NULL,
  `phone_number` bigint(20) NOT NULL,
  `location` varchar(200) NOT NULL,
  `user_picture` varchar(200) NOT NULL,
  `profile_view` bigint(20) NOT NULL,
  `facebook_id` bigint(11) NOT NULL,
  `facebook_status` tinyint(4) NOT NULL,
  `login_status` tinyint(4) NOT NULL,
  `status` tinyint(4) NOT NULL,
  `activation_link` varchar(200) NOT NULL,
  `password_link` varchar(200) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;

首先使用以下代码创建视图文件。我把它放在views/users/signup.ctp

<div class="grid_7 alpha">
    <a href="Javascript:void(0);" onclick="connect_facebook(); return false;">
      Signup with facebook
    </a>
</div>

应用一些 css 使它看起来更漂亮。现在在同一个视图文件中,在页面底部添加以下代码。

<script type="text/javascript">
    window.fbAsyncInit = function()
    {
        FB.init(
        {
            appId: FACEBOOK_API,
            cookie: true,
            xfbml: true,
            oauth: true
        });
    };

    function connect_facebook()
    {
        FB.login(function(response)
        {
            if (response.authResponse)
            {
                $.ajax(
                {
                    url         : HOST+'users/facebook_signup/'+response.authResponse.userID,
                    dataType    : 'json',
                    beforeSend  : function()
                    {
                        $.blockUI({
                            message: '<img src="'+HOST+'img/popup/pre_code_bg.gif" alt="" />'
                        });
                    },
                    success     : function(data)
                    {
                        $.unblockUI();
                        if(data.status == "false")
                        {
                            FB.logout(function(response)
                            {
                                window.location = HOST+'users/logout';
                            });
                            return false;
                        }
                        else
                        {
                            document.location.reload(true);
                        }
                    }
                });
            }
            else
            {
                FB.logout(function(response)
                {
                    window.location = HOST+'users/logout';
                    alert('User cancelled login or did not fully authorize.');
                });
            }
        });
    }

    (function()
    {
        var e = document.createElement('script'); e.async = true;
        e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
        document.getElementById('fb-signup-root').appendChild(e);
    }());
</script>

只需相应地更换FACEBOOK_API

现在在users_controller文件里面粘贴下面的代码,

<?php
class UsersController extends AppController
{
    var $name = 'Users';

    function beforeFilter()
    {
        parent::beforeFilter();
        $this->Auth->allow( 'login','signup''facebook_signup' );
    }

    function facebook_signup($facebook_id)
    {
        $this->autoRender = false;
        $this->layout = "ajax";

        App::import('Vendor', 'Facebook', array('file' => 'facebook'.DS.'facebook.php'));

        $response = array();

        $facebook = new Facebook(array
        (
            'appId'  => FACEBOOK_API,
            'secret' => FACEBOOK_SKEY,
        ));

        $facebook_user = $facebook->getUser();

        if ($facebook_user)
        {
            try
            {
                $user_profile = $facebook->api('/me');
            }
            catch (FacebookApiException $e)
            {
                echo '<pre>'.htmlspecialchars(print_r($e, true)).'</pre>';
                $facebook_user = null;
            }
        }

        $find_facebookemail = $this->User->find('first',array
        (
            'conditions' => array
            (
                'User.email' => $user_profile['email'],
                'OR' => array
                (
                    'User.facebook_id' => 0,
                    'User.facebook_id' => $facebook_id
                )

            ),
            'recursive' => -1
        ));

        if(!empty($find_facebookemail))
        {
            $this->data['User']['id'] = $find_facebookemail['User']['id'];
            $this->data['User']['email'] = $find_facebookemail['User']['email'];
            $this->data['User']['name'] = $find_facebookemail['User']['name'];
            $this->data['User']['facebook_id'] = $find_facebookemail['User']['facebook_id'];
            $this->data['User']['location'] = $find_facebookemail['User']['location'];
            $this->data['User']['dob'] = $find_facebookemail['User']['dob'];

            $this->Session->write("Auth.User", $find_facebookemail['User']);
            $this->Session->write("Auth.User.facebook_user", true);

            $response['status'] = "true";
            echo json_encode($response);
            exit;
        }
        else
        {
            $this->data['User']['email'] = $user_profile['email'];
            $this->data['User']['name'] = $user_profile['name'];
            $this->data['User']['facebook_id'] = $user_profile['id'];
            $this->data['User']['location'] = $user_profile['location']['name'];
            $this->data['User']['facebook_status'] = 1;
            $this->data['User']['status'] = 1;

            $dob = explode("/",$user_profile['birthday']);
            $this->data['User']['dob'] = $dob[2].'-'.$dob[0].'-'.$dob[1];

            if($this->User->save($this->data['User']))
            {
                $this->Session->write("Auth.User.id", $this->User->getLastInsertID());
                $this->Session->write("Auth.User.name", $this->data['User']['name']);
                $this->Session->write("Auth.User.email", $this->data['User']['email']);
                $this->Session->write("Auth.User.facebook_id", $this->data['User']['facebook_id']);
                $this->Session->write("Auth.User.location", $this->data['User']['location']);
                $this->Session->write("Auth.User.dob", $this->data['User']['dob']);
                $this->Session->write("Auth.User.facebook_user", true);

                $img = file_get_contents('https://graph.facebook.com/'.$find_facebookemail['User']['facebook_id'].'/picture?width=500&height=500');
                $img_thumbs = file_get_contents('https://graph.facebook.com/'.$find_facebookemail['User']['facebook_id'].'/picture?width=150&height=150');

                $file = "img".DS."user_picture".DS."".$find_facebookemail['User']['facebook_id'].".jpg";
                $file_thumbs = "img".DS."user_picture".DS."thumbs".DS."".$find_facebookemail['User']['facebook_id'].".jpg";

                file_put_contents($file, $img);
                file_put_contents($file_thumbs, $img_thumbs);

                $this->data['User']['id'] = $this->Session->read('Auth.User.id');
                $this->data['User']['user_picture'] = $find_facebookemail['User']['facebook_id'].".jpg";

                $this->User->save($this->data['User']);

                $response['message'] = "You have successfully registered with us.";
                $response['status'] = "true";
                echo json_encode($response);
                exit;
            }
            else
            {
                $response['message'] = "Something is wrong during process.Please try again later.";
                $response['status'] = "false";
                echo json_encode($response);
                exit;
            }
        }
        exit;
    }
}

控制器代码所做的是检查facebook具有已发布 ID 的用户是否已经注册,然后允许他login访问站点并设置cakephp auth.user 会话,如果没有,则将用户和他/她的图片以及所有其他数据添加到 mysql 数据库中。

现在您的数据库中有用户条目,因此您可以在他/她更改密码后要求用户更改他的密码,然后他们可以在没有帐户login的情况下访问您的应用程序。loginfacebook

上面的代码经过多次全面测试并且可以正常工作。

完毕。

于 2013-03-05T08:35:52.543 回答
1

数据库表结构:通常您的常规用户表包含姓名、电子邮件、生日等以及包含 Facebook 用户 ID 的附加字段。我称之为“facebook_uid”。这将为您提供与 Facebook API 相关的识别目的。如果您需要在用户注销您的应用程序时做一些事情,那么您将需要一个名为“access_token”的附加字段。此访问令牌以及正确的权限将允许您在用户离线时代表用户执行操作,例如在他的墙上发帖等。

答案 1.)如果用户已经在您的应用程序中注册了 Facebook,您只需检查 Facebook API 调用中出现的 Facebook 用户 ID 并将其与您的用户表匹配。如果找到,那么您就可以像往常一样使用 CakePHP 处理本地会话。如果未找到,则表示是新用户,他们必须完成注册过程。

答案 2.)将手动注册用户和 Facebook 注册用户关联起来的唯一数据是他们的电子邮件。如果本地邮箱与Facebook邮箱匹配,则表示是同一用户,只需更新数据库中的“facebook_uid”字段,下次他登录时,你就已经可以识别他了。如果 Facebook 电子邮件与他在您网站上注册时使用的电子邮件不同,那么您无法知道是同一个人。您可以随时查看其他信息,例如姓名、生日和其他信息,但这根本不可靠,您可能会弄乱您的用户数据。此外,您不需要 2 张桌子。您的原始用户表已经有“facebook_uid”字段。

答案 3.)就像我之前解释的那样,如果您需要在用户注销时在用户的 Facebook 帐户上做一些事情,例如在他的墙上发帖或喜欢某事,您将只需要访问令牌。为了得到他的访问令牌,你只需要从你的 Facebook API 类中调用 getAccessToken() 方法:

$this->Facebook->Sdk->getAccessToken();

这将返回一个长字符串,您可以将其存储在您的用户表中,然后检索它以在他的 Facebook 帐户上执行任务。以下是基于 CodeIgniter 的 Wall 帖子示例:

$facebook = new Facebook(array(
  'appId'  => 'XXXXXXXXXXXXXXXXXXXX',
  'secret' => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
));

$facebook->setAccessToken($row->access_token); //this access token was previously stored in the database

$args = array(
    'message'   => 'Ya estoy participando en el Concurso - Se la Estrella',
    'link'      => $this->config->item('tabUrl'),
    'name'      => 'Concurso - Se la Estrella de Kreisel',
    'caption'   => '¡Vota por mi video! Tu también puedes participar.',
    'picture'   => site_url().'/assets/main/uploads/captures/'.$row->facebook_id.'.jpg'
);

$post_id = $facebook->api("/me/feed", "post", $args);

另外,我个人对您的注册表单的建议:不要让用户修改或查看表单上的 Facebook 信息,只需询问他您可能需要 Facebook 不会提供的任何其他信息,例如他的电话、公司等。 姓名等信息、姓氏、电子邮件、生日等已在 Facebook 上,显示已填写此数据的表单会使用户感到困惑。所以,如果用户在 Facebook 上注册,你几乎不需要问他什么,只需检查用户是否已经存在于你的本地数据库中,如果存在,你登录他,如果不存在,只是保存他的数据。

于 2013-03-04T16:43:24.803 回答
0

是的,您需要将帐户链接在一起。

我通常为用户添加facebook_id列。因此,每当我的用户想要使用 FB 登录或获得积极的身份验证响应时

function connectWithFacebook() {
    FB.getLoginStatus(function(response) {
    var uid = '';
    var accessToken = '';
    if (response.status === 'connected') {
        uid = response.authResponse.userID;
        accessToken = response.authResponse.accessToken;
        FB.api('/me', function(response) {
            $.post("http://" + AppSettings.baseURL + "/Users/checkState", 
            {data : response}, 
            function(postResponse){
                if(postResponse == 'registered') {
                    // do after registration stuff
                } else if( postResponse == 'authenticated') {
                        // do after login stuff
                    }
            });
        });
    }
 });
}

FB.Event.subscribe('auth.login', function () {
    connectWithFacebook();
});

在控制器方面。

public function checkState() {
    $userExists = $this->User->userExists($this->request->data['id']);
    if (!empty($userExists)) {         
        $this->authorizeUser($userExists);  // Already exisits, login user to our system with id
        echo "authorized";
        return;
    }
    if ($this->request->is('post')) {
        $this->User->create();
        $this->request->data['User']['role_id'] = 4;

        if ($this->User->save($this->request->data, array('validate' => false))) {
            echo "registered";
        }
        return;
    }
}

对于不使用 Facebook 注册的用户,facebook_id 列保持为 0。

我希望这有帮助

于 2013-03-03T02:24:18.613 回答