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

简介: from:http://leyteris.iteye.com/blog/1483403        这几天一直在搞OAuth2.0的东西,写SDK啥的,为了更加深入的了解服务端的OAuth验证机制,就自己动手搭了个php下OAuth的环境,并且将它移植到了自己比较熟的tp框架里。 废话不少说,开动。   其实网上是有OAuth2.0的php版本的。 你可以在http://c

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模式下我认为更好!

目录
相关文章
|
2月前
|
SQL 安全 PHP
PHP 自发布以来一直在 Web 开发领域占据重要地位,PHP 8 更是带来了属性、刚性类型等新特性。
【10月更文挑战第1天】PHP 自问世以来,凭借其易用性和灵活性,在 Web 开发领域迅速崛起。从简单的网页脚本语言逐步演进为支持面向对象编程的现代语言,尤其自 PHP 5.3 引入命名空间后,代码组织和维护变得更加高效。PHP 7 的性能优化和 PHP 8 的新特性(如属性和刚性类型)进一步巩固了其地位。框架如 Laravel、Symfony、Yii2 和 CodeIgniter 等简化了开发流程,提高了效率和安全性。
50 2
|
21天前
|
SQL 安全 PHP
PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全
本文深入探讨了PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全。
42 4
|
28天前
|
API PHP 数据库
PHP中哪个框架最适合做API?
在数字化时代,API作为软件应用间通信的桥梁至关重要。本文探讨了PHP中适合API开发的主流框架,包括Laravel、Symfony、Lumen、Slim、Yii和Phalcon,分析了它们的特点和优势,帮助开发者选择合适的框架,提高开发效率、保证接口稳定性和安全性。
50 3
|
1月前
|
SQL 安全 PHP
探索PHP的现代演进:从Web开发到框架创新
PHP是一种流行的服务器端脚本语言,自诞生以来在Web开发领域占据重要地位。从简单的网页脚本到支持面向对象编程的现代语言,PHP经历了多次重大更新。本文探讨PHP的现代演进历程,重点介绍其在Web开发中的应用及框架创新,如Laravel、Symfony等。这些框架不仅简化了开发流程,还提高了开发效率和安全性。
27 3
|
1月前
|
SQL 安全 PHP
探索PHP的现代演进:从Web开发到框架创新
PHP 自发布以来一直在 Web 开发领域占据重要地位,历经多次重大更新,从简单的脚本语言进化为支持面向对象编程的现代语言。本文探讨 PHP 的演进历程,重点介绍其在 Web 开发中的应用及框架创新。自 PHP 5.3 引入命名空间后,PHP 迈向了面向对象编程时代;PHP 7 通过优化内核大幅提升性能;PHP 8 更是带来了属性、刚性类型等新特性。
27 3
|
1月前
|
XML 安全 PHP
PHP与SOAP Web服务开发:基础与进阶教程
本文介绍了PHP与SOAP Web服务的基础和进阶知识,涵盖SOAP的基本概念、PHP中的SoapServer和SoapClient类的使用方法,以及服务端和客户端的开发示例。此外,还探讨了安全性、性能优化等高级主题,帮助开发者掌握更高效的Web服务开发技巧。
|
3月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
49 2
|
3月前
|
消息中间件 NoSQL Go
PHP转Go系列 | ThinkPHP与Gin框架之Redis延时消息队列技术实践
【9月更文挑战第7天】在从 PHP 的 ThinkPHP 框架迁移到 Go 的 Gin 框架时,涉及 Redis 延时消息队列的技术实践主要包括:理解延时消息队列概念,其能在特定时间处理消息,适用于定时任务等场景;在 ThinkPHP 中使用 Redis 实现延时队列;在 Gin 中结合 Go 的 Redis 客户端库实现类似功能;Go 具有更高性能和简洁性,适合处理大量消息。迁移过程中需考虑业务需求及系统稳定性。
|
4月前
|
缓存 中间件 PHP
Laravel 框架:优雅 PHP Web 开发的典范
【8月更文挑战第31天】
129 0
|
4月前
|
安全 Java 云计算
JSF 应用究竟何去何从?云端部署能否成为其全新突破点?快来一探究竟!
【8月更文挑战第31天】本文介绍了将JavaServer Faces(JSF)应用部署到云平台的过程。首先,根据成本、功能、可靠性和安全性选择合适的云平台。接着,展示了构建简单JSF应用的示例代码。最后,以AWS Elastic Beanstalk为例,详细说明了部署流程。部署至云端可提升应用的可用性、扩展性和安全性。
50 0