PHP搭建OAuth2.0

时间:2023-01-03 12:44:39

这几天一直在搞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的更多相关文章

  1. Microsoft&period;Owin&period;Security&period;OAuth搭建OAuth2&period;0授权服务端

    Microsoft.Owin.Security.OAuth搭建OAuth2.0授权服务端 目录 前言 OAuth2.0简介 授权模式 (SimpleSSO示例) 使用Microsoft.Owin.Se ...

  2. 【PHP】基于ThinkPHP框架搭建OAuth2&period;0服务

    [PHP]基于ThinkPHP框架搭建OAuth2.0服务 http://leyteris.iteye.com/blog/1483403

  3. 使用DotNetOpenAuth搭建OAuth2&period;0授权框架

    标题还是一如既往的难取. 我认为对于一个普遍问题,必有对应的一个简洁优美的解决方案.当然这也许只是我的一厢情愿,因为根据宇宙法则,所有事物总归趋于混沌,而OAuth协议就是混沌中的产物,不管是1.0. ...

  4. Owin中间件搭建OAuth2&period;0认证授权服务体会

    继两篇转载的Owin搭建OAuth 2.0的文章,使用Owin中间件搭建OAuth2.0认证授权服务器和理解OAuth 2.0之后,我想把最近整理的资料做一下总结. 前两篇主要是介绍概念和一个基本的D ...

  5. 使用Owin中间件搭建OAuth2&period;0认证授权服务器

    前言 这里主要总结下本人最近半个月关于搭建OAuth2.0服务器工作的经验.至于为何需要OAuth2.0.为何是Owin.什么是Owin等问题,不再赘述.我假定读者是使用Asp.Net,并需要搭建OA ...

  6. DotNetOpenAuth搭建OAuth2&period;0

    使用DotNetOpenAuth搭建OAuth2.0授权框架 标题还是一如既往的难取. 我认为对于一个普遍问题,必有对应的一个简洁优美的解决方案.当然这也许只是我的一厢情愿,因为根据宇宙法则,所有事物 ...

  7. &lbrack;2014-11-11&rsqb;使用Owin中间件搭建OAuth2&period;0认证授权服务器

    前言 这里主要总结下本人最近半个月关于搭建OAuth2.0服务器工作的经验.至于为何需要OAuth2.0.为何是Owin.什么是Owin等问题,不再赘述.我假定读者是使用Asp.Net,并需要搭建OA ...

  8. C&num;搭建Oauth2&period;0认证流程以及代码示例

    我认为对于一个普遍问题,必有对应的一个简洁优美的解决方案.当然这也许只是我的一厢情愿,因为根据宇宙法则,所有事物总归趋于混沌,而OAuth协议就是混沌中的产物,不管是1...0a还是2.,单看版本号就 ...

  9. Spring Cloud 微服务中搭建 OAuth2&period;0 认证授权服务

    在使用 Spring Cloud 体系来构建微服务的过程中,用户请求是通过网关(ZUUL 或 Spring APIGateway)以 HTTP 协议来传输信息,API 网关将自己注册为 Eureka ...

  10. SimpleSSO&colon;使用Microsoft&period;Owin&period;Security&period;OAuth搭建OAuth2&period;0授权服务端

    目录 前言 OAuth2.0简介 授权模式 (SimpleSSO示例) 使用Microsoft.Owin.Security.SimpleSSO模拟OpenID认证 通过authorization co ...

随机推荐

  1. Python调用服务接口

    #! /usr/bin/env python # coding=utf-8 ############################################################## ...

  2. JQuery源码解析(十一)

    内存泄露 什么是内存泄露? 内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束.在C++中,因为是手动管理内存,内存泄露是经常出现的事情.而现在流行的C#和Java等语言采用了自动 ...

  3. Application&comma;Session和Cookie

    做ASP.NET,肯定会和这几个对象打交道,这些也是基础面试的常见题目,总结一下还是必要的,好在大神已经总结好了,直接参考就好了: http://www.cnblogs.com/breezeblew/ ...

  4. Java与C/C&plus;&plus;的区别

        首先应该清楚,Java是由C++发展而来的,它保留了c++的大部分内容,类似于c++,但句法更清晰,规模更小,更易学.它是在对多种程序设计语言进行了深入细致研究的基础上,据弃了其他语言的不足之 ...

  5. mysql修改连接数

    方法一:   进入MySQL安装目录 打开MySQL配置文件 my.ini 或 my.cnf查找 max_connections=100 修改为 max_connections=1000 服务里重起M ...

  6. docker 学习笔记(2)--doucker file命令

    FROM base       ---- imageRUN                  ---- 执行命令ADD   ---- 添加文件COPY         ---- 拷贝文件CMD    ...

  7. MySQL的索引与优化

    写在前面:索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点.考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录.如果没有索引,查询将 ...

  8. &lbrack;Spring&rsqb; Resource 资源

    import ch.qos.logback.core.net.SyslogOutputStream; import org.springframework.core.io.ClassPathResou ...

  9. 洛谷P2894&lbrack;USACO08FEB&rsqb;酒店Hotel(线段树)

    问题描述 奶牛们最近的旅游计划,是到苏必利尔湖畔,享受那里的湖光山色,以及明媚的阳光.作为整个旅游的策划者和负责人,贝茜选择在湖边的一家著名的旅馆住宿.这个巨大的旅馆一共有N (1 <= N & ...

  10. HDU1520 Anniversary party 树形DP基础

    There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The Un ...