zoukankan      html  css  js  c++  java
  • 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模式下我认为更好!

  • 相关阅读:
    javascript--setTimeout定时器
    javascript--BOM的onload事件和onunload事件
    JavaScript--文本框中只允许输入数字的操作(其他字符不显示)
    JavaScript--获取页面盒子中鼠标相对于盒子上、左边框的坐标
    javascript--事件对象e的来源、意义、应用及其属性的用法 function(e){}
    javascript--select标签的添加删除功能的使用
    JavaScript--动态添加元素(纯js书写table并删除数据)
    MyBatis快速入门
    《大型网站技术架构》学习笔记-01概述
    FreeMarker快速入门
  • 原文地址:https://www.cnblogs.com/hubing/p/4266574.html
Copyright © 2011-2022 走看看