-
-
Save emdeeeks/75139460dae26b683e5a596eafea2756 to your computer and use it in GitHub Desktop.
Facebook Custom Authenticate Object for CakePHP 3.x and Facebook PHP SDK 5.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Auth; | |
use Cake\Auth\BaseAuthenticate; | |
use Cake\Network\Request; | |
use Cake\Network\Response; | |
use Cake\Core\Configure; | |
use Cake\Event\Event; | |
use Cake\Network\Session; | |
use Facebook; | |
/** | |
* Class FacebookAuthenticate | |
* | |
* Custom Facebook Authentication Object for Facebook PHP_SDK 5 and for CakePHP 3.x | |
* | |
* Insert this file into src/Auth/ folder of your app. | |
* | |
* To use a Facebook config file, you should have a facebook.php file in your config folder like | |
* | |
* <?php | |
* return [ | |
* 'Facebook.app_id' => 'YOUR_APP_ID', | |
* 'Facebook.app_secret' => 'YOUR_APP_SECRET' | |
* ]; | |
* | |
* and use Configure::load('facebook', 'default'); in your bootstrap.php. | |
* | |
* In your user controller, add $this->Auth->config() into your overridden initialize method: | |
* | |
* public function initialize() | |
* { | |
* parent::initialize(); | |
* $this->Auth->config('authenticate', | |
* ['Form', | |
* 'Facebook' // app authentication object. | |
* ]); | |
* } | |
* | |
* You also need to have in your composer.json to use this class. | |
* | |
* "require": { | |
* "facebook/php-sdk-v4" : "~5.0", | |
* "guzzlehttp/guzzle": "^6.1" | |
* }, | |
* | |
* | |
* @link http://book.cakephp.org/3.0/en/controllers/components/authentication.html#creating-custom-authentication-objects | |
* @link https://developers.facebook.com/docs/php/howto/example_facebook_login | |
* @package App\Auth | |
*/ | |
class FacebookAuthenticate extends BaseAuthenticate | |
{ | |
/** | |
* @var Facebook\Facebook | |
*/ | |
private $facebookObject; | |
/** | |
* @var Facebook\Helpers\FacebookRedirectLoginHelper | |
*/ | |
private $helper; | |
/** | |
* Constructor | |
* | |
* To use Facebook config, you should have a facebook.php in your config folder like | |
* <?php | |
* return [ | |
* 'Facebook.app_id' => 'YOUR_APP_ID', | |
* 'Facebook.app_secret' => 'YOUR_APP_SECRET' | |
* ]; | |
* and use Configure::load('facebook', 'default'); in your bootstrap.php. | |
* | |
* @param \Cake\Controller\ComponentRegistry $registry The Component registry used on this request. | |
* @param array $config Array of config to use. | |
*/ | |
public function __construct(\Cake\Controller\ComponentRegistry $registry, array $config = []) | |
{ | |
parent::__construct($registry, $config); | |
$this->facebookObject = new Facebook\Facebook([ | |
'app_id' => Configure::read('Facebook.app_id'), | |
'app_secret' => Configure::read('Facebook.app_secret'), | |
'default_graph_version' => 'v2.5', | |
]); | |
$this->helper = $this->facebookObject->getRedirectLoginHelper(); | |
} | |
/** | |
* Implemented Abstract Method for Facebook. | |
* | |
* @param Request $request | |
* @param Response $response | |
* @return array|bool | |
*/ | |
public function authenticate(Request $request, Response $response) | |
{ | |
$accessToken = $this->getAccessToken(); | |
if ($accessToken) { | |
$user = $this->getFacebookUser($accessToken); | |
//$accessToken = $this->exchangeAccessToken($accessToken); | |
$request->session()->write('fb_access_token', (string)$accessToken); | |
return $user; | |
} else { | |
$response->location($this->generateLoginUrl()); | |
} | |
return false; | |
} | |
/** | |
* TODO: Insert login url into facebook config. | |
* | |
* @return string | |
*/ | |
public function generateLoginUrl() | |
{ | |
$permissions = ['email', 'user_likes']; // optional | |
$loginUrl = $this->helper->getLoginUrl('http://' . $_SERVER['SERVER_NAME'] . '/users/login', $permissions); | |
return $loginUrl; | |
} | |
/** | |
* Changes access token based on example on the link | |
* | |
* @link https://developers.facebook.com/docs/php/howto/example_facebook_login | |
* @param $accessToken | |
* @return Facebook\Authentication\AccessToken | |
*/ | |
private function exchangeAccessToken($accessToken) | |
{ | |
if (!$accessToken->isLongLived()) { | |
$oAuth2Client = $this->facebookObject->getOAuth2Client(); | |
// Exchanges a short-lived access token for a long-lived one | |
try { | |
$accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken); | |
} catch (Facebook\Exceptions\FacebookSDKException $e) { | |
echo "<p>Error getting long-lived access token: " . $this->helper->getMessage() . "</p>\n\n"; | |
exit; | |
} | |
} | |
return $accessToken; | |
} | |
/** | |
* Returns Facebook user array. | |
* | |
* @param string $accessToken | |
* @return array | |
*/ | |
private function getFacebookUser(string $accessToken) | |
{ | |
try { | |
// Returns a `Facebook\FacebookResponse` object | |
$response = $this->facebookObject->get('/me?fields=id,name,email', $accessToken); | |
} catch (Facebook\Exceptions\FacebookResponseException $e) { | |
echo 'Graph returned an error: ' . $e->getMessage(); | |
exit; | |
} catch (Facebook\Exceptions\FacebookSDKException $e) { | |
echo 'Facebook SDK returned an error: ' . $e->getMessage(); | |
exit; | |
} | |
$user = $response->getGraphUser(); | |
return ['facebook' => $user['id'], 'username' => $user['name'], 'email' => $user['email']]; | |
} | |
/** | |
* Private method to get Facebook access token. Sometimes returns null. | |
* | |
* @return string | |
*/ | |
private function getAccessToken() | |
{ | |
try { | |
$accessToken = $this->helper->getAccessToken(); | |
} catch (Facebook\Exceptions\FacebookResponseException $e) { | |
// When Graph returns an error | |
echo 'Graph returned an error: ' . $e->getMessage(); | |
exit; | |
} catch (Facebook\Exceptions\FacebookSDKException $e) { | |
// When validation fails or other local issues | |
echo 'Facebook SDK returned an error: ' . $e->getMessage(); | |
exit; | |
} finally { | |
return $accessToken; | |
} | |
} | |
/** | |
* Returns a list of all events that this authenticate class will listen to. | |
* | |
* An authenticate class can listen to following events fired by AuthComponent: | |
* | |
* - `Auth.afterIdentify` - Fired after a user has been identified using one of | |
* configured authenticate class. The callback function should have signature | |
* like `afterIdentify(Event $event, array $user)` when `$user` is the | |
* identified user record. | |
* | |
* - `Auth.logout` - Fired when AuthComponent::logout() is called. The callback | |
* function should have signature like `logout(Event $event, array $user)` | |
* where `$user` is the user about to be logged out. | |
* | |
* @return array List of events this class listens to. Defaults to `[]`. | |
*/ | |
public function implementedEvents() | |
{ | |
return [ | |
'Auth.logout' => 'logout' | |
]; | |
} | |
/** | |
* Logs you out of the app, but does not log you out of Facebook. | |
* Clever isn't it? :) | |
* | |
* @param Event $event | |
* @param array $user | |
*/ | |
public function logout(Event $event, array $user) | |
{ | |
if ($user['facebook']) { | |
$request = Request::createFromGlobals(); | |
$accessToken = $request->session()->read('fb_access_token'); | |
$this->facebookObject->delete('me/permissions', [], $accessToken); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment