php - 如果已通过身份验证并且用户存在于数据库中,则将 Facebook 用户登录到 CakePHP 应用程序

标签 php facebook cakephp

我构建了一个非常简单的 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 进行身份验证,这使用了我的 Controller 的 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/我应该在上面发布的两种方法之间创建一个额外的步骤来处理代码并取回访问 token 。

但我已经访问了填写注册表单所需的所有必需信息,而无需执行 OAuth 流程的第二阶段并获取访问 token !所以不确定我是否需要它这种情况……还是我?如果是的话,它如何帮助解决前两个问题?

最佳答案

以下是允许用户通过 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 ;

首先创建包含以下代码的 View 文件。我把它放在 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 使其看起来更漂亮。现在在同一 View 文件中,在页面底部添加以下代码。

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

Controller 代码所做的是检查是否有发布 ID 的 facebook 用户已经注册 然后允许他登录 到站点并设置 cakephp auth.user session 如果没有,则将用户和他/她的照片以及所有其他数据添加到 mysql 数据库中

现在您的数据库中有用户条目,因此您可以要求用户更改他的密码,一旦他/她更改了密码,他们就可以login 到您的应用程序,而无需 login in到 facebook 帐户。

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

完成。

关于php - 如果已通过身份验证并且用户存在于数据库中,则将 Facebook 用户登录到 CakePHP 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15124894/

相关文章:

PHP strtotime 给出某些月份的错误日期

javascript - react ( Facebook ): managed state of controlled checkboxes

facebook - 视频源和图形 API

php - CakePHP的contain()方法看到同一个表的belongsToMany而不是belongsTo

css - cakephp,给蛋糕表单自定义样式

javascript - 获取多个下拉列表的值并使用 javascript 比较每个下拉列表

php - Laravel 5 类 'form' 未找到

php - 由于 google 的图片代理,Gmail 中的图片链接中断

android - 部署并获利 - 了解 React Native 入门中的第 10 步

Cakephp 2.3 $this->Auth->allow() 未按预期工作