FuelPHPã§opauthã使ã£ã¦è²ããªãã°ã¤ã³ã«å¯¾å¿ãã¦ã¿ã
FuelPHPã§opauthã使ã£ã¦è²ããªãã°ã¤ã³ã«å¯¾å¿ãã¦ã¿ã¾ããã
ãã°ã¤ã³ã®ãã¿ã¼ã³ã¯
1.é常ã®usernameã¨passwordã®ãã°ã¤ã³
2.Twitterã®oauthãã°ã¤ã³
3.Facebookã®oauthãã°ã¤ã³
ã§ãã
Twitterã¨Facebookã®ãã°ã¤ã³ã«ã¤ãã¦ã¯fuel-opauthã使ã£ã¦ãã¾ãããこちらの参考ブログ記事ã«ãè¨è¼ããã¦ããéãnamespaceã®è¨å®ã«ä¸å
·åãããããgithubã§forkãããã®ãsubmoduleåãã¦ãã¾ãã
本家 https://github.com/andreoav/fuel-opauth本家
修正版 https://github.com/letsspeak/fuel-opauth
ä»åä½æãããå¤æ´ãããã¡ã¤ã«ã¯ä¸éãgistã«ãã¢ãããã¼ããã¦ãã¾ãã
ä¸å
·åã¯ãã¤ãéã触ããªããä¿®æ£ãã¦ããããã¨æã£ã¦ãã¾ãããåé¡ç¹ãªã©ããã¾ããããæ°è»½ã«ãé£çµ¡ãã ããã
gist
https://gist.github.com/letsspeak/5229245
fuel-opauthã®submoduleå
git submodule add https://github.com/letsspeak/fuel-opauth.git fuel/app/packages/opauth/
TIPS
githubããhttps://ã§submoduleåããå ´åãå 容ã®å¤æ´ãçºçããã¨ãã®pushæã«ä¸è¨ä¿®æ£ãå¿ è¦ãªã®ã§æ³¨æã
fuel/packages/opauth/.git/config
- url = https://github.com/letsspeak/fuel-opauth + url = ssh://[email protected]/letsspeak/fuel-opauth.git
opauth.phpã®è¨å®
ã½ã«ãã¨Twitter/Facebookã®éçºè ç¨ã®ãã¼ãç»é²ããã
fuel/app/config/opauth.php
<?php namespace Opauth; return array( 'path' => '/auth/login/', 'callback_url' => '/auth/callback/', 'security_salt' => 'ã©ã³ãã ãªæååãçæãã¦ç»é²ãã', 'Strategy' => array( 'Facebook' => array( 'app_id' => 'Facebookã§åå¾ããã¢ããªID / APIãã¼', 'app_secret' => 'Facebookã§åå¾ããã¢ããªã®ã·ã¼ã¯ã¬ãããã¼' ), 'Twitter' => array( 'key' => 'Consumer key', 'secret' => 'Consumer secret' ), ), );
User/TwitterUser/FacebookUserãä½æ
oil g model user name:string password:string nickname:string email:string last_login:int oil g model twitteruser uid:string token:string secret:string user_id:int oil g model facebookuser uid:string token:string expires:int user_id:int
ãã¤ã°ã¬ã¼ã·ã§ã³ã®å¤æ´ç¹
ã¹ãã¬ã¼ã¸ã¨ã³ã¸ã³ã¯å
¨ã¦InnoDBã«å¤æ´ã
Userã§ä¸å
管çãããã¨ãæ³å®ãã¦User->last_login以å¤ã¯ãã¹ã¦'null'=>trueã«è¨å®ã
ã¢ãã«ã¯ã©ã¹åãModel_TwitterUserã«å¤æ´ãããã®ã§ãã¼ãã«åãtwitter_usersã«å¤æ´ã
ã¢ãã«ã¯ã©ã¹åãModel_FacebookUserã«å¤æ´ãããã®ã§ãã¼ãã«åãfacebook_usersã«å¤æ´ã
ã¢ãã«ã®å¤æ´ç¹
ã¢ãã«ã¯ã©ã¹åãããããModel_TwitterUserãModel_FacebookUserã«å¤æ´ã
Model_UserãModel_TwitterUserãModel_FacebookUserã®ããªãã¼ã·ã§ã³è¿½å ã
authã³ã³ããã¼ã©ã¼ãä½æ
é常ãã°ã¤ã³æã¯å¼æ°ç¡ã㧠/auth/login/ã«POSTããã
Twitterãã°ã¤ã³æã¯/auth/login/twitter/ãå©ãã
Facebookãã°ã¤ã³æã¯/auth/login/facebook/ãå©ãã
fuel/app/classes/controller/auth.php
<?php class Controller_Auth extends Controller { private $_config = null; private $_salt_length = null; private $_iteration_count = null; public function before() { if(!isset($this->_config)) { $this->_config = Config::load('opauth', 'opauth'); } $this->_salt_length = 32; $this->_iteration_count = 10; } // auth/login/* public function action_login($_provider = null, $method = null) { // å¼æ°ç¡ãæã¯é常ãã°ã¤ã³ if (is_null($_provider)) return $this->normal_login(); // http://domainname/auth/login/twitter/oauth_callback?denied=signature if ($method === 'oauth_callback') { if (Input::get('denied')){ return $this->login_failed(); } } if(array_key_exists(Inflector::humanize($_provider), Arr::get($this->_config, 'Strategy'))) { $_oauth = new Opauth($this->_config, true); } else { return $this->login_failed(); } } // é常ãã°ã¤ã³ public function normal_login() { $username = Input::post('username'); $password = Input::post('password'); // ã¦ã¼ã¶ã¼åã¨ãã¹ã¯ã¼ã空æ¬æã¯ãã°ã¤ã³ãã©ã¼ã ã表示ãã if (is_null($username) and is_null($password)) { return Response::forge(View::forge('auth/form')); } // èªè¨¼ $query = Model_User::query()->where('name', $username); if ($query->count() === 0){ // èªè¨¼ã¨ã©ã¼ $this->login_failed(); } // ãã¹ã¯ã¼ãã®ããã·ã¥å $user = $query->get_one(); $salt = substr($user->password, 0, $this->_salt_length); $enc_password = $salt.$password; for ($i = 0; $i < $this->_iteration_count; $i++) { $enc_password = sha1($enc_password); } if ($user->password === $salt.$enc_password){ // èªè¨¼æå return $this->login_succeeded($user->id); }else{ // èªè¨¼ã¨ã©ã¼ $this->login_failed(); } } public function action_signup() { $username = Input::post('username'); $password = Input::post('password'); // ã¦ã¼ã¶ã¼åã¨ãã¹ã¯ã¼ã空æ¬æã¯ãµã¤ã³ã¢ãããã©ã¼ã ã表示ãã if (is_null($username) and is_null($password)) { return Response::forge(View::forge('auth/signup')); } // ãµã¤ã³ã¢ããå¦ç // ãã¹ã¯ã¼ãã®ããã·ã¥å $salt = substr(md5(uniqid(rand(), true)), 0, $this->_salt_length); $enc_password = $salt.$password; for ($i = 0; $i < $this->_iteration_count; $i++) { $enc_password = sha1($enc_password); } // ããªãã¼ã·ã§ã³ $val = Model_User::validate('create'); $input = array( 'name' => $username, 'password' => $salt.$enc_password, 'last_login' => \Date::time()->get_timestamp(), ); if ($val->run($input)) { // ããªãã¼ã·ã§ã³æåæ $user = Model_User::forge($input); if ($user and $user->save()) { // ãµã¤ã³ã¢ããæåæ return $this->login_succeeded($user->id); } else { // ãµã¤ã³ã¢ãã失ææ return $this->login_failed(); } } else { // ããªãã¼ã·ã§ã³å¤±ææ $data['errors'] = $val->error(); return Response::forge(View::forge('auth/signup', $data)); } } public function action_test1() { return Response::forge(View::forge('auth/test')); } public function action_test2() { return Response::forge(View::forge('auth/test')); } public function action_test3() { return Response::forge(View::forge('auth/test')); } // Twitter / Facebook ãã°ã¤ã³æå/失ææã«å¼ã°ãã public function action_callback() { $_opauth = new Opauth($this->_config, false); switch($_opauth->env['callback_transport']) { case 'session': session_start(); $response = $_SESSION['opauth']; unset($_SESSION['opauth']); break; } if (array_key_exists('error', $response)) { return $this->login_failed(); // echo '<strong style="color: red;">Authentication error: </strong> Opauth returns error auth response.'."<br>\n"; } else { if (empty($response['auth']) || empty($response['timestamp']) || empty($response['signature']) || empty($response['auth']['provider']) || empty($response['auth']['uid'])) { return $this->login_failed(); // echo '<strong style="color: red;">Invalid auth response: </strong>Missing key auth response components.'."<br>\n"; } elseif (!$_opauth->validate(sha1(print_r($response['auth'], true)), $response['timestamp'], $response['signature'], $reason)) { return $this->login_failed(); // echo '<strong style="color: red;">Invalid auth response: </strong>'.$reason.".<br>\n"; } else { // Twitter / Facebook ãã°ã¤ã³æå return $this->opauth_login($response); } } } public function opauth_login($response = null) { $provider = $response['auth']['provider']; if ($provider === 'Twitter') return $this->twitter_login($response); if ($provider === 'Facebook') return $this->facebook_login($response); } public function twitter_login($response = null) { $uid = (string) $response['auth']['uid']; $query = Model_TwitterUser::query()->where('uid', $uid); if ($query->count() == 0) { // TwitterUseræªç»é²ã®å ´åã¯ãµã¤ã³ã¢ãã return $this->twitter_signup($response); } // TwitterUserç»é²æ¸ã¿ã®å ´åã¯ãã°ã¤ã³ $twitter_user = $query->get_one(); return $this->login_succeeded($twitter_user->user_id); } public function facebook_login($response = null) { $uid = $response['auth']['uid']; $query = Model_FacebookUser::query()->where('uid', $uid); if ($query->count() == 0) { // FacebookUseræªç»é²ã®å ´åã¯ãµã¤ã³ã¢ãã return $this->facebook_signup($response); } // FacebookUserç»é²æ¸ã¿ã®å ´åã¯ãã°ã¤ã³ $facebook_user = $query->get_one(); return $this->login_succeeded($facebook_user->user_id); } public function twitter_signup($response = null) { // ããªãã¼ã·ã§ã³ $val = Model_TwitterUser::validate('create'); $input = array( 'uid' => (string) $response['auth']['uid'], 'token' => $response['auth']['credentials']['token'], 'secret' => $response['auth']['credentials']['secret'], ); if ($val->run($input)) { // ããªãã¼ã·ã§ã³æåæ $user = Model_User::forge(array( 'nickname' => $response['auth']['info']['nickname'], 'last_login' => \Date::time()->get_timestamp(), )); $twitter_user = Model_TwitterUser::forge($input); if ($user and $twitter_user) { // ã¦ã¼ã¶ã¼çææå try { \DB::start_transaction(); if ($user->save() === false) { // Userä¿å失æ throw new \Exception('user save failed.'); } $twitter_user->user_id = $user->id; if ($twitter_user->save() === false) { // TwitterUserä¿å失æ throw new \Exception('twitter_user save failed.'); } // Userã¨TwitterUserã®ä¿åæå \DB::commit_transaction(); return $this->login_succeeded($user->id); } catch (\Exception $e) { \DB::rollback_transaction(); return $this->login_failed(); } } else { // ã¦ã¼ã¶ã¼çæ失æ return $this->login_failed(); } } else { // ããªãã¼ã·ã§ã³å¤±ææ return $this->login_failed(); } } public function facebook_signup($response = null) { // ããªãã¼ã·ã§ã³ $val = Model_FacebookUser::validate('create'); $expires = strtotime($response['auth']['credentials']['expires']); $input = array( 'uid' => (string) $response['auth']['uid'], 'token' => $response['auth']['credentials']['token'], 'expires' => $expires, ); if ($val->run($input)) { // ããªãã¼ã·ã§ã³æåæ $user = Model_User::forge(array( 'nickname' => $response['auth']['info']['name'], 'last_login' => \Date::time()->get_timestamp(), )); $facebook_user = Model_FacebookUser::forge($input); if ($user and $facebook_user) { // ã¦ã¼ã¶ã¼çææå try { \DB::start_transaction(); if ($user->save() === false) { // Userä¿å失æ throw new \Exception('user save failed.'); } $facebook_user->user_id = $user->id; if ($facebook_user->save() === false) { // FacebookUserä¿å失æ throw new \Exception('facebook_user save failed.'); } // Userã¨FacebookUserã®ä¿åæå \DB::commit_transaction(); return $this->login_succeeded($user->id); } catch (\Exception $e) { \DB::rollback_transaction(); return $this->login_failed(); } } else { // ã¦ã¼ã¶ã¼çæ失æ return $this->login_failed(); } } else { // ããªãã¼ã·ã§ã³å¤±ææ return $this->login_failed(); } } public function login_succeeded($user_id) { Session::set('user_id', $user_id); Response::redirect('auth/test1'); } public function login_failed() { return Response::redirect('auth/test1'); } public function action_logout() { Session::delete('user_id'); Response::redirect('auth/test1'); } }
æ¸å¿µç¹ãªã©
ã»ã¨ããããä½ã£ãã ããªã®ã§å
¨ç¶èå¼±ãªæ°ãããã
ã»XSRF対çããã¦ããªãã
ã»ããã¶login_failed()ã«é£ã°ãã¦ãããã©ããã®ï¼
ã»ç¹å®ã®ãã¼ã¸ã§ãã°ã¤ã³ãçµç±ãã¦ç¹å®ã®ãã¼ã¸ã«å¾©å¸°ãããããªãã¨ã¯èæ
®ããã¦ããªãã
ã»ãã¹ã¯ã¼ãã¯ãã¡ããããã·ã¥åãã¦ã¿ãã
ã»Usersã§ã®ä¸æ¬ç®¡çã«æå³ãããã®ã...