如果经过身份验证并且用户存在于DB中,则将Facebook用户记录到CakePHP应用程序中

时间:2013-02-27 23:52:45

标签: 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进行身份验证,并使用我的控制器的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端有什么特别的东西?我正在考虑在Users表中搜索匹配的帐户,然后自动登录,但是在FB身份验证发生后,我没有在网上找到任何验证您自己的用户表的示例。

问题2。)可能与之前的问题相关,但是当用户注册帐户时,与他们用于登录的Facebook帐户无关联,因此如果他们尝试再次使用登录除非我在数据库中搜索类似的细节,否则Facebook将无法看到该关联,但这似乎非常不稳定,而且没有正确使用API​​。基本上,用户刚刚使用FB来填充表单,而不是使用他们的Facebook帐户进行实际注册。

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

e.g。用于存储FB用户和CakePHP App用户之间链接的新表:

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

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

问题3。)当用户通过Facebook发回注册表单时,他们会获得以下网址(出于安全原因,注意位已被更改):

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流程的第二阶段并获取访问令牌!所以不确定我是否需要它这种情况......或者我呢?如果是这样的话,如果能够解决前两个问题怎么会有帮助?

3 个答案:

答案 0 :(得分: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;
    }
}

控制器代码执行的操作是检查已发布ID的facebook用户是否已注册然后允许他login到站点并设置 cakephp auth.user session 如果没有,那么将用户和他/她的图片与所有其他数据一起添加到mysql数据库

现在您在数据库中有用户输入,因此您可以在用户更改密码后请求使用更改密码,然后他们可以login向您的应用程序login进入facebook帐户。

以上代码经过多次全面测试并正常运行。

DONE。

答案 1 :(得分: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();

这将返回一个长字符串,您可以将其存储在users表中,然后检索它以在其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,您几乎不需要向他询问任何其他内容,只需检查用户是否已存在于您的本地数据库中,如果存在,则将其登录,如果不存在,只需保存他的数据。

答案 2 :(得分: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。

我希望这会有所帮助