教学之友,学习之友。

站长教学网

当前位置: 站长教学网 > 开源代码 > 框架 >

ThinkPHP框架如何架设OAuth2.0服务

时间:2013-01-08 22:58来源:未知 作者:ken 点击:

同学们可以先看看什么是oauth,转载百度百科一句话:OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。具体就要自己搜索了解下。

这几天一直在搞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 站长教学网 eduyo.com
  * @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;
  }
}
 

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

 

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` int(20) default NULL,
  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");
      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来继承它达到受限的目的,如下:教学网 eduyo.com 

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

(责任编辑:ken)
TAG标签: 框架 thinkphp oauth
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
注册登录:不允许匿名留言,登录后留言无需输入验证码。
用户名: 验证码:点击我更换图片
栏目列表
最新内容