2013-02-27 48 views
3

我建立了一個非常簡單的CakePHP的應用程序來測試出一個可能的實現Facebook的PHP SDK的,使用戶可以註冊或者使用的應用或Facebook,也可以登錄使用應用程序或Facebook。但是因爲用戶可以在應用上做些事情,即使他們通過他們的Facebook帳戶登錄/註冊,他們也會在應用上擁有用戶帳戶。登錄Facebook的用戶進入CakePHP的應用程序,如果認證和用戶存在於數據庫

到目前爲止,我已經創建了處理身份驗證和獲取用戶信息的方法有兩種:

// 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傳遞的一個,但在DB中相同的電子郵件地址存在,因爲如果他們改變了什麼呢?我想過或許將Facebook用戶標識存儲在應用中的用戶標識表中,以便存儲連接。這是一個解決方案嗎?或者錯誤的方式來做到這一點?

例如新表來存儲用戶FB和CakePHP App用戶之間的聯繫:

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進程的第二階段並獲取訪問令牌!所以不知道我是否需要這種情況...或者我呢?如果是的話,它將如何協助解決前兩個問題?

+0

你寫道:'用戶可以使用應用程序或Facebook註冊,也可以使用應用程序或Facebook登錄。我看不出你的意思。你能糾正它嗎?順便說一句,你能否清楚地說出你是否也計劃讓用戶在沒有Facebook的情況下連接?這意味着你會讓用戶創建賬戶和管理密碼。 – 2013-03-02 22:14:56

+0

是的,用戶可以創建一個沒有Facebook的帳戶。但是,如果他們確實使用Facebook,那麼他們仍然會在Facebook用戶ID鏈接到的應用程序端擁有一個帳戶。 – Cameron 2013-03-03 12:09:05

回答

0

是的,你會REQD的帳戶關聯起來。

我通常添加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

我希望這有助於

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的牆壁後的一個例子:

$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

以下是允許用戶通過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與貼出的編號爲已經註冊然後讓他login到現場,並設置CakePHP的auth.user會話如果不是那麼添加用戶和他/她的圖片與所有其他數據到mysql數據庫

現在你有你的數據庫中的用戶條目,以便你可以要求使用,一旦他/她到facebook帳戶更改密碼,然後他們可以login到您的應用程序,而login更改其密碼。

上面的代碼已經完全測試過一次以上,並且工作正常。

DONE。

+0

永遠不要在自動增量字段中存儲Facebook ID。讓我告訴你爲什麼,控制器在DB中註冊一個fb id爲121212 [1]的用戶,所以現在當一個非FB用戶註冊到應用程序時,id將是121212 [2],這將繼續所有非FB用戶。所以當一個真正的用戶ID爲121212 [2]時,你會有衝突。您的控制器將驗證錯誤的用戶。 – 2013-03-08 03:38:45

+1

@KishorKundan你見過DB嗎?我有'facebook_id' bigint(11)NOT NULL, – 2013-03-08 03:42:49

+0

對不起我的壞! :D錯過了。 在另一個筆記上,爲什麼你要保持你的控制器代碼這麼厚?您的控制器代碼幾乎處理了應該委派給Model,View和ExceptionHandling的所有東西。 – 2013-03-08 03:50:08

相關問題