PHP搭建OAuth2.0
這幾天一直在搞OAuth2.0的東西,寫SDK啥的,為了更加深入的了解服務端的OAuth驗證機制,就自己動手搭了個php下OAuth的環境,并且將它移植到了自己比較熟的tp框架里。
廢話不多說,開動。
?
其實網上是有OAuth2.0的php版本的。
你可以在http://code.google.com/p/oauth2-php/?找到源代碼,上面實現了PDO和MongoDB的數據模式。這里我也是基于這些代碼在TP中進行整合的。
?
好,這里我們可以把下載下來的包解壓,把Lib下的OAuth.inc改名為OAuth2.class.php后放到tp核心包下的目錄下:
?
/Extend/Library/ORG/OAuth/OAuth2.class.php接下來我們要繼承這個類;
在這個目錄下新建一個ThinkOAuth2.class.php文件:
?
<?php /*** @category ORG* @package ORG* @author Leyteris* @version 2012.3.16*/// OAUTH2_DB_DSN 數據庫連接DSN // OAUTH2_CODES_TABLE 服務器表名稱 // OAUTH2_CLIENTS_TABLE 客戶端表名稱 // OAUTH2_TOKEN_TABLE 驗證碼表名稱import("ORG.OAuth.OAuth2");class ThinkOAuth2 extends OAuth2 {private $db;private $table;/*** 構造*/public function __construct() {parent::__construct();$this -> db = Db::getInstance(C('OAUTH2_DB_DSN'));$this -> table = array('auth_codes'=>C('OAUTH2_CODES_TABLE'),'clients'=>C('OAUTH2_CLIENTS_TABLE'),'tokens'=>C('OAUTH2_TOKEN_TABLE'));}/*** 析構*/function __destruct() {$this->db = NULL; // Release db connection}private function handleException($e) {echo "Database error: " . $e->getMessage();exit;}/**** 增加client* @param string $client_id* @param string $client_secret* @param string $redirect_uri*/public function addClient($client_id, $client_secret, $redirect_uri) {$time = time();$sql = "INSERT INTO {$this -> table['clients']} "."(client_id, client_secret, redirect_uri, create_time) VALUES ("{$client_id}", "{$client_secret}", "{$redirect_uri}","{$time}")";$this -> db -> execute($sql);}/*** Implements OAuth2::checkClientCredentials()* @see OAuth2::checkClientCredentials()*/protected function checkClientCredentials($client_id, $client_secret = NULL) {$sql = "SELECT client_secret FROM {$this -> table['clients']} "."WHERE client_id = "{$client_id}"";$result = $this -> db -> query($sql);if ($client_secret === NULL) {return $result !== FALSE;}//Log::write("checkClientCredentials : ".$result);//Log::write("checkClientCredentials : ".$result[0]);//Log::write("checkClientCredentials : ".$result[0]["client_secret"]);return $result[0]["client_secret"] == $client_secret;}/*** Implements OAuth2::getRedirectUri().* @see OAuth2::getRedirectUri()*/protected function getRedirectUri($client_id) {$sql = "SELECT redirect_uri FROM {$this -> table['clients']} "."WHERE client_id = "{$client_id}"";$result = $this -> db -> query($sql);if ($result === FALSE) {return FALSE;}//Log::write("getRedirectUri : ".$result);//Log::write("getRedirectUri : ".$result[0]);//Log::write("getRedirectUri : ".$result[0]["redirect_uri"]);return isset($result[0]["redirect_uri"]) && $result[0]["redirect_uri"] ? $result[0]["redirect_uri"] : NULL;}/*** Implements OAuth2::getAccessToken().* @see OAuth2::getAccessToken()*/protected function getAccessToken($access_token) {$sql = "SELECT client_id, expires, scope FROM {$this -> table['tokens']} "."WHERE access_token = "{$access_token}"";$result = $this -> db -> query($sql);//Log::write("getAccessToken : ".$result);//Log::write("getAccessToken : ".$result[0]);return $result !== FALSE ? $result : NULL;}/*** Implements OAuth2::setAccessToken().* @see OAuth2::setAccessToken()*/protected function setAccessToken($access_token, $client_id, $expires, $scope = NULL) {$sql = "INSERT INTO {$this -> table['tokens']} "."(access_token, client_id, expires, scope) "."VALUES ("{$access_token}", "{$client_id}", "{$expires}", "{$scope}")";$this -> db -> execute($sql);}/*** Overrides OAuth2::getSupportedGrantTypes().* @see OAuth2::getSupportedGrantTypes()*/protected function getSupportedGrantTypes() {return array(OAUTH2_GRANT_TYPE_AUTH_CODE);}/*** Overrides OAuth2::getAuthCode().* @see OAuth2::getAuthCode()*/protected function getAuthCode($code) {$sql = "SELECT code, client_id, redirect_uri, expires, scope "."FROM {$this -> table['auth_codes']} WHERE code = "{$code}"";$result = $this -> db -> query($sql);//Log::write("getAuthcode : ".$result);//Log::write("getAuthcode : ".$result[0]);//Log::write("getAuthcode : ".$result[0]["code"]);return $result !== FALSE ? $result[0] : NULL;}/*** Overrides OAuth2::setAuthCode().* @see OAuth2::setAuthCode()*/protected function setAuthCode($code, $client_id, $redirect_uri, $expires, $scope = NULL) {$time = time();$sql = "INSERT INTO {$this -> table['auth_codes']} "."(code, client_id, redirect_uri, expires, scope) "."VALUES ("${code}", "${client_id}", "${redirect_uri}", "${expires}", "${scope}")";$result = $this -> db -> execute($sql);}/*** Overrides OAuth2::checkUserCredentials().* @see OAuth2::checkUserCredentials()*/protected function checkUserCredentials($client_id, $username, $password){return TRUE;} }?
?
在這里我們需要創建數據庫:
?
SQL代碼: CREATE TABLE `oauth_client` (`id` bigint(20) NOT NULL auto_increment,`client_id` varchar(32) NOT NULL,`client_secret` varchar(32) NOT NULL,`redirect_uri` varchar(200) NOT NULL,`create_time`?timestamp NOT NULL DEFAULT NOW(),?PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;CREATE TABLE `oauth_code` (`id` bigint(20) NOT NULL auto_increment,`client_id` varchar(32) NOT NULL,`user_id` varchar(32) NOT NULL,`code` varchar(40) NOT NULL,`redirect_uri` varchar(200) NOT NULL,`expires` int(11) NOT NULL,`scope` varchar(250) default NULL,PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;CREATE TABLE `oauth_token` (`id` bigint(20) NOT NULL auto_increment,`client_id` varchar(32) NOT NULL,`user_id` varchar(32) NOT NULL,`access_token` varchar(40) NOT NULL,`refresh_token` varchar(40) NOT NULL,`expires` int(11) NOT NULL,`scope` varchar(200) default NULL,PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;?
?
上面的數據庫表名可以自己隨便定;但是要在config.php配置表名:
?
'OAUTH2_CODES_TABLE'=>'oauth_code', 'OAUTH2_CLIENTS_TABLE'=>'oauth_client', 'OAUTH2_TOKEN_TABLE'=>'oauth_token',?
如果OAuth的服務器不是當前服務器,那就要指定下DSN地址了:
?
?
'OAUTH2_DB_DSN'=>'mysql://root:mima@l:3306/database'?
好了,大致的核心庫代碼就是如此。接下來要使用它
?
我們創建一個OAuth的Action負責OAuth2的一些驗證(OauthAction.class.php)
?
import("ORG.OAuth.ThinkOAuth2");class OauthAction extends Action {private $oauth = NULL;function _initialize(){header("Content-Type: application/json");<span style="white-space: pre;"> </span>header("Cache-Control: no-store");$this -> oauth = new ThinkOAuth2();}public function index(){header("Content-Type:application/json; charset=utf-8");$this -> ajaxReturn(null, 'oauth-server-start', 1, 'json');}public function access_token() {$this -> oauth -> grantAccessToken();}//權限驗證public function authorize() {if ($_POST) {$this -> oauth -> finishClientAuthorization($_POST["accept"] == "Yep", $_POST);return;}///表單準備$auth_params = $this -> oauth -> getAuthorizeParams();$this -> assign("params", $auth_params);$this->display();}public function addclient() {if ($_POST && isset($_POST["client_id"]) &&isset($_POST["client_secret"]) &&isset($_POST["redirect_uri"])) {$this -> oauth -> addClient($_POST["client_id"], $_POST["client_secret"], $_POST["redirect_uri"]);return;}$this->display();} }?
這里我們創建了一個私有的oauth對象并在初始化的時候去init它。
?
以上的代碼在password那個部分沒有做驗證,第三種模式需要把ThinkOAuth類中的checkUserCredentials方法進行重寫。
?
繼續我們寫一個受限資源代碼。我們這里沒有用AOP進行攔截,所以我準備直接用一個基類來模擬攔截。
?
?
import("ORG.OAuth.ThinkOAuth2");class BaseAction extends Action {protected $oauth = NULL;function _initialize(){$this -> oauth = new ThinkOAuth2();}public function index(){if(!$this -> oauth -> verifyAccessToken()){$this -> ajaxReturn(null, 'no,no,no', 0, 'json');exit();}$this -> ajaxReturn(null, 'oauth-server', 1, 'json');}}?
接下來直接用一個UserAction來繼承它達到受限的目的,如下:
?
?
class UserAction extends BaseAction {public function index(){if(!$this -> oauth -> verifyAccessToken()){$this -> ajaxReturn(null, 'no,no,no', 0, 'json');}$this -> ajaxReturn(null, 'oauth-server', 1, 'json');}}?
?
?
?
最后說明一點,為什么要把user_id耦合 進OAuth的表呢?因為我們有時候需要從access_token返查user_id,上面的表就能解決這個問題,但其實還有一種方式是在對于 access_token生成的時候自動包含user_id再進行加密,在解碼的時候從access_token直接取出user_id就可以了。這里關 于user_id和密碼驗證的都沒有去實現,需要后期繼承ThinkOAuth2類或者修改checkUserCredentials方法才能實現的。?另外這套東西用在REST模式下我認為更好!
總結
以上是生活随笔為你收集整理的PHP搭建OAuth2.0的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zookeeper配置
- 下一篇: MySQL的诡异同步问题-重复执行一条r