【PHP】基于ThinkPHP框架搭建OAuth2.0服务

from:http://leyteris.iteye.com/blog/1483403

       这几天一直在搞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核心包下的目录下:

 

Tree代码   收藏代码
  1. /Extend/Library/ORG/OAuth/OAuth2.class.php  

 

接下来我们要继承这个类;

在这个目录下新建一个ThinkOAuth2.class.php文件:

 

Php代码   收藏代码
  1. <?php  
  2. /** 
  3.  * @category ORG 
  4.  * @package ORG 
  5.  * @author Leyteris 
  6.  * @version 2012.3.16 
  7.  */  
  8.   
  9. // OAUTH2_DB_DSN  数据库连接DSN  
  10. // OAUTH2_CODES_TABLE 服务器表名称  
  11. // OAUTH2_CLIENTS_TABLE 客户端表名称  
  12. // OAUTH2_TOKEN_TABLE 验证码表名称  
  13.   
  14. import("ORG.OAuth.OAuth2");  
  15.   
  16. class ThinkOAuth2 extends OAuth2 {  
  17.   
  18.     private $db;  
  19.     private $table;  
  20.   
  21.     /** 
  22.      * 构造 
  23.      */  
  24.     public function __construct() {  
  25.         parent::__construct();  
  26.         $this -> db = Db::getInstance(C('OAUTH2_DB_DSN'));  
  27.         $this -> table = array(  
  28.             'auth_codes'=>C('OAUTH2_CODES_TABLE'),  
  29.             'clients'=>C('OAUTH2_CLIENTS_TABLE'),  
  30.             'tokens'=>C('OAUTH2_TOKEN_TABLE')  
  31.         );  
  32.     }  
  33.   
  34.     /** 
  35.      * 析构 
  36.      */  
  37.     function __destruct() {  
  38.         $this->db = NULL; // Release db connection  
  39.     }  
  40.   
  41.     private function handleException($e) {  
  42.         echo "Database error: " . $e->getMessage();  
  43.         exit;  
  44.     }  
  45.   
  46.     /** 
  47.      *  
  48.      * 增加client 
  49.      * @param string $client_id 
  50.      * @param string $client_secret 
  51.      * @param string $redirect_uri 
  52.      */  
  53.     public function addClient($client_id$client_secret$redirect_uri) {  
  54.           
  55.         $time = time();  
  56.         $sql = "INSERT INTO {$this -> table['clients']} ".  
  57.             "(client_id, client_secret, redirect_uri, create_time) VALUES (\"{$client_id}\", \"{$client_secret}\", \"{$redirect_uri}\",\"{$time}\")";  
  58.           
  59.         $this -> db -> execute($sql);  
  60.           
  61.     }  
  62.   
  63.     /** 
  64.      * Implements OAuth2::checkClientCredentials() 
  65.      * @see OAuth2::checkClientCredentials() 
  66.      */  
  67.     protected function checkClientCredentials($client_id$client_secret = NULL) {  
  68.           
  69.         $sql = "SELECT client_secret FROM {$this -> table['clients']} ".  
  70.             "WHERE client_id = \"{$client_id}\"";  
  71.           
  72.         $result = $this -> db -> query($sql);  
  73.         if ($client_secret === NULL) {  
  74.             return $result !== FALSE;  
  75.         }  
  76.           
  77.         //Log::write("checkClientCredentials : ".$result);  
  78.         //Log::write("checkClientCredentials : ".$result[0]);  
  79.         //Log::write("checkClientCredentials : ".$result[0]["client_secret"]);  
  80.           
  81.         return $result[0]["client_secret"] == $client_secret;  
  82.           
  83.     }  
  84.   
  85.     /** 
  86.      * Implements OAuth2::getRedirectUri(). 
  87.      * @see OAuth2::getRedirectUri() 
  88.      */  
  89.     protected function getRedirectUri($client_id) {  
  90.           
  91.         $sql = "SELECT redirect_uri FROM {$this -> table['clients']} ".  
  92.             "WHERE client_id = \"{$client_id}\"";  
  93.           
  94.         $result = $this -> db -> query($sql);  
  95.           
  96.         if ($result === FALSE) {  
  97.             return FALSE;  
  98.         }  
  99.           
  100.         //Log::write("getRedirectUri : ".$result);  
  101.         //Log::write("getRedirectUri : ".$result[0]);  
  102.         //Log::write("getRedirectUri : ".$result[0]["redirect_uri"]);  
  103.           
  104.         return isset($result[0]["redirect_uri"]) && $result[0]["redirect_uri"] ? $result[0]["redirect_uri"] : NULL;  
  105.           
  106.     }  
  107.   
  108.     /** 
  109.      * Implements OAuth2::getAccessToken(). 
  110.      * @see OAuth2::getAccessToken() 
  111.      */  
  112.     protected function getAccessToken($access_token) {  
  113.           
  114.         $sql = "SELECT client_id, expires, scope FROM {$this -> table['tokens']} ".  
  115.             "WHERE access_token = \"{$access_token}\"";  
  116.           
  117.         $result = $this -> db -> query($sql);  
  118.           
  119.         //Log::write("getAccessToken : ".$result);  
  120.         //Log::write("getAccessToken : ".$result[0]);  
  121.           
  122.         return $result !== FALSE ? $result : NULL;  
  123.           
  124.     }  
  125.   
  126.     /** 
  127.      * Implements OAuth2::setAccessToken(). 
  128.      * @see OAuth2::setAccessToken() 
  129.      */  
  130.     protected function setAccessToken($access_token$client_id$expires$scope = NULL) {  
  131.           
  132.         $sql = "INSERT INTO {$this -> table['tokens']} ".  
  133.             "(access_token, client_id, expires, scope) ".  
  134.             "VALUES (\"{$access_token}\", \"{$client_id}\", \"{$expires}\", \"{$scope}\")";  
  135.           
  136.         $this -> db -> execute($sql);  
  137.           
  138.     }  
  139.   
  140.     /** 
  141.      * Overrides OAuth2::getSupportedGrantTypes(). 
  142.      * @see OAuth2::getSupportedGrantTypes() 
  143.      */  
  144.     protected function getSupportedGrantTypes() {  
  145.         return array(  
  146.             OAUTH2_GRANT_TYPE_AUTH_CODE  
  147.         );  
  148.     }  
  149.   
  150.     /** 
  151.      * Overrides OAuth2::getAuthCode(). 
  152.      * @see OAuth2::getAuthCode() 
  153.      */  
  154.     protected function getAuthCode($code) {  
  155.           
  156.         $sql = "SELECT code, client_id, redirect_uri, expires, scope ".  
  157.             "FROM {$this -> table['auth_codes']} WHERE code = \"{$code}\"";  
  158.           
  159.         $result = $this -> db -> query($sql);  
  160.           
  161.         //Log::write("getAuthcode : ".$result);  
  162.         //Log::write("getAuthcode : ".$result[0]);  
  163.         //Log::write("getAuthcode : ".$result[0]["code"]);  
  164.           
  165.         return $result !== FALSE ? $result[0] : NULL;  
  166.   
  167.     }  
  168.   
  169.     /** 
  170.      * Overrides OAuth2::setAuthCode(). 
  171.      * @see OAuth2::setAuthCode() 
  172.      */  
  173.     protected function setAuthCode($code$client_id$redirect_uri$expires$scope = NULL) {  
  174.           
  175.         $time = time();  
  176.         $sql = "INSERT INTO {$this -> table['auth_codes']} ".  
  177.             "(code, client_id, redirect_uri, expires, scope) ".  
  178.             "VALUES (\"${code}\", \"${client_id}\", \"${redirect_uri}\", \"${expires}\", \"${scope}\")";  
  179.           
  180.         $result = $this -> db -> execute($sql);  
  181.   }  
  182.     
  183.   /** 
  184.    * Overrides OAuth2::checkUserCredentials(). 
  185.    * @see OAuth2::checkUserCredentials() 
  186.    */  
  187.   protected function checkUserCredentials($client_id$username$password){  
  188.     return TRUE;  
  189.   }  
  190. }  

 

 在这里我们需要创建数据库:

 

Sql代码   收藏代码
  1. CREATE TABLE `oauth_client` (  
  2.   `id` bigint(20) NOT NULL auto_increment,  
  3.   `client_id` varchar(32) NOT NULL,  
  4.   `client_secret` varchar(32) NOT NULL,  
  5.   `redirect_uri` varchar(200) NOT NULL,  
  6.   `create_time` int(20) default NULL,  
  7.   PRIMARY KEY  (`id`)  
  8. ) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;  
  9.   
  10. CREATE TABLE `oauth_code` (  
  11.   `id` bigint(20) NOT NULL auto_increment,  
  12.   `client_id` varchar(32) NOT NULL,  
  13.   `user_id` varchar(32) NOT NULL,  
  14.   `code` varchar(40) NOT NULL,  
  15.   `redirect_uri` varchar(200) NOT NULL,  
  16.   `expires` int(11) NOT NULL,  
  17.   `scope` varchar(250) default NULL,  
  18.   PRIMARY KEY  (`id`)  
  19. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;  
  20.   
  21. CREATE TABLE `oauth_token` (  
  22.   `id` bigint(20) NOT NULL auto_increment,  
  23.   `client_id` varchar(32) NOT NULL,  
  24.   `user_id` varchar(32) NOT NULL,  
  25.   `access_token` varchar(40) NOT NULL,  
  26.   `refresh_token` varchar(40) NOT NULL,  
  27.   `expires` int(11) NOT NULL,  
  28.   `scope` varchar(200) default NULL,  
  29.   PRIMARY KEY  (`id`)  
  30. ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;  
 

 

上面的数据库表名可以自己随便定;但是要在config.php配置表名:

 

Php代码   收藏代码
  1. 'OAUTH2_CODES_TABLE'=>'oauth_code',  
  2. 'OAUTH2_CLIENTS_TABLE'=>'oauth_client',  
  3. 'OAUTH2_TOKEN_TABLE'=>'oauth_token',  

 

如果OAuth的服务器不是当前服务器,那就要指定下DSN地址了:

 

 

Php代码   收藏代码
  1. 'OAUTH2_DB_DSN'=>'mysql://root:mima@l:3306/database'  

 

 

好了,大致的核心库代码就是如此。接下来要使用它

 

我们创建一个OAuth的Action负责OAuth2的一些验证(OauthAction.class.php)

 

Php代码   收藏代码
  1. import("ORG.OAuth.ThinkOAuth2");  
  2.   
  3. class OauthAction extends Action {  
  4.       
  5.     private $oauth = NULL;  
  6.   
  7.     function _initialize(){  
  8.           
  9.         header("Content-Type: application/json");  
  10.         <span style="white-space: pre;">    </span>header("Cache-Control: no-store");  
  11.         $this -> oauth = new ThinkOAuth2();  
  12.   
  13.     }  
  14.       
  15.     public function index(){  
  16.           
  17.         header("Content-Type:application/json; charset=utf-8");  
  18.         $this -> ajaxReturn(null, 'oauth-server-start', 1, 'json');  
  19.           
  20.     }  
  21.       
  22.     public function access_token() {  
  23.           
  24.         $this -> oauth -> grantAccessToken();  
  25.   
  26.     }  
  27.       
  28.     //权限验证  
  29.     public function authorize() {  
  30.           
  31.         if ($_POST) {  
  32.             $this -> oauth -> finishClientAuthorization($_POST["accept"] == "Yep"$_POST);  
  33.             return;  
  34.         }  
  35.           
  36.         ///表单准备  
  37.         $auth_params = $this -> oauth -> getAuthorizeParams();  
  38.         $this -> assign("params"$auth_params);  
  39.         $this->display();  
  40.   
  41.     }  
  42.       
  43.     public function addclient() {  
  44.           
  45.         if ($_POST && isset($_POST["client_id"]) &&  
  46.          isset($_POST["client_secret"]) &&   
  47.             isset($_POST["redirect_uri"])) {  
  48.                   
  49.             $this -> oauth -> addClient($_POST["client_id"], $_POST["client_secret"], $_POST["redirect_uri"]);  
  50.             return;  
  51.         }  
  52.           
  53.         $this->display();  
  54.     }  
  55. }  
 

 

这里我们创建了一个私有的oauth对象并在初始化的时候去init它。

 

以上的代码在password那个部分没有做验证,第三种模式需要把ThinkOAuth类中的checkUserCredentials方法进行重写。

 

继续我们写一个受限资源代码。我们这里没有用AOP进行拦截,所以我准备直接用一个基类来模拟拦截。

 

 

Php代码   收藏代码
  1. import("ORG.OAuth.ThinkOAuth2");  
  2.   
  3. class BaseAction extends Action {  
  4.       
  5.     protected $oauth = NULL;  
  6.   
  7.     function _initialize(){  
  8.           
  9.         $this -> oauth = new ThinkOAuth2();  
  10.   
  11.     }  
  12.       
  13.     public function index(){  
  14.           
  15.         if(!$this -> oauth -> verifyAccessToken()){  
  16.             $this -> ajaxReturn(null, 'no,no,no', 0, 'json');  
  17.             exit();  
  18.         }  
  19.         $this -> ajaxReturn(null, 'oauth-server', 1, 'json');  
  20.           
  21.     }  
  22.       
  23. }  

 

 接下来直接用一个UserAction来继承它达到受限的目的,如下:

 

 

Php代码   收藏代码
  1. class UserAction extends BaseAction {  
  2.       
  3.     public function index(){  
  4.   
  5.         if(!$this -> oauth -> verifyAccessToken()){  
  6.             $this -> ajaxReturn(null, 'no,no,no', 0, 'json');  
  7.         }  
  8.         $this -> ajaxReturn(null, 'oauth-server', 1, 'json');  
  9.           
  10.     }  
  11.       
  12. }  
 

 

 

 

最后说明一点,为什么要把user_id耦合进OAuth的表呢?因为我们有时候需要从access_token返查user_id,上面的表就能解决这个问题,但其实还有一种方式是在对于access_token生成的时候自动包含user_id再进行加密,在解码的时候从access_token直接取出user_id就可以了。这里关于user_id和密码验证的都没有去实现,需要后期继承ThinkOAuth2类或者修改checkUserCredentials方法才能实现的。 另外这套东西用在REST模式下我认为更好!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值