Oauth授权码讲解&Php Oauth2实现

什么是Oauth2?

Oauth 是开放网络标识,目前版本为2.0所以叫做Oauth2。

为什么要用Oauth2?

举个例子,比如说你要登录XX网站,但是XX网站需要注册登录,非常麻烦,并且如果所有的网站都需要登录的话,非常不便于记忆,那么如果我们只注册一个网站,其他网站通过我们在这个XXX网站的登录状态不就一举两得了吗!并且我们可以获取到XX网站的公共信息,比如昵称啊,所在城市啊这类的,也方便其他网站信息的扩展.

授权的流程

  +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

摘自 RFC6749

客户端授权模式

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

授权码形式:

  +----------+
     | Resource |
     |   Owner  |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier      +---------------+
     |         -+----(A)-- & Redirection URI ---->|               |
     |  User-   |                                 | Authorization |
     |  Agent  -+----(B)-- User authenticates --->|     Server    |
     |          |                                 |               |
     |         -+----(C)-- Authorization Code ---<|               |
     +-|----|---+                                 +---------------+
       |    |                                         ^      v
      (A)  (C)                                        |      |
       |    |                                         |      |
       ^    v                                         |      |
     +---------+                                      |      |
     |         |>---(D)-- Authorization Code ---------'      |
     |  Client |          & Redirection URI                  |
     |         |                                             |
     |         |<---(E)----- Access Token -------------------'
     +---------+       (w/ Optional Refresh Token)

(A) 用户访问客户端,后者将其转发到认证服务器

(B) 用户选择是否给客户端授权

(C) 如果用户给授权的话,认证服务器将用户导向事前设置好的uri,同时附上一个auth_code

(D) 客户端收到授权码,附上早先的URI,向认证服务器申请令牌

(E)认证服务器核对授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token) 和更新令牌(refresh token)

实战:

那么我们讲下如何使用php 搭建 Oauth2

首先我们安装一个composer依赖

composer require bshaffer/oauth2-server-php "~1.8" (前提是你安装了composer依赖)

OR 使用git clone的方式

mkdir my-oauth2-walkthrough
cd my-oauth2-walkthrough
git clone https://github.com/bshaffer/oauth2-server-php.git -b master

下载完之后创建表

CREATE TABLE oauth_clients (client_id VARCHAR(80) NOT NULL, client_secret VARCHAR(80), redirect_uri VARCHAR(2000) NOT NULL, grant_types VARCHAR(80), scope VARCHAR(100), user_id VARCHAR(80), CONSTRAINT clients_client_id_pk PRIMARY KEY (client_id));
CREATE TABLE oauth_access_tokens (access_token VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(255), expires TIMESTAMP NOT NULL, scope VARCHAR(2000), CONSTRAINT access_token_pk PRIMARY KEY (access_token));
CREATE TABLE oauth_authorization_codes (authorization_code VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(255), redirect_uri VARCHAR(2000), expires TIMESTAMP NOT NULL, scope VARCHAR(2000), CONSTRAINT auth_code_pk PRIMARY KEY (authorization_code));
CREATE TABLE oauth_refresh_tokens (refresh_token VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(255), expires TIMESTAMP NOT NULL, scope VARCHAR(2000), CONSTRAINT refresh_token_pk PRIMARY KEY (refresh_token));
CREATE TABLE oauth_users (username VARCHAR(255) NOT NULL, password VARCHAR(2000), first_name VARCHAR(255), last_name VARCHAR(255), CONSTRAINT username_pk PRIMARY KEY (username));
CREATE TABLE oauth_scopes (scope TEXT, is_default BOOLEAN);
CREATE TABLE oauth_jwt (client_id VARCHAR(80) NOT NULL, subject VARCHAR(80), public_key VARCHAR(2000), CONSTRAINT jwt_client_id_pk PRIMARY KEY (client_id));

创建一个BootsTrap引导文件 [server.php]

Bootstrap your OAuth2 Server

We need to create and configure our OAuth2 Server object. This will be used by all the endpoints in our application. Name this file server.php:

$dsn      = 'mysql:dbname=my_oauth2_db;host=localhost';
$username = 'root';
$password = '';

// error reporting (this is a demo, after all!)
ini_set('display_errors',1);error_reporting(E_ALL);

// Autoloading (composer is preferred, but for this example let's just do this)
require_once('oauth2-server-php/src/OAuth2/Autoloader.php');
OAuth2\Autoloader::register();

// $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost"
$storage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));

// Pass a storage object or array of storage objects to the OAuth2 server class
$server = new OAuth2\Server($storage);

// Add the "Client Credentials" grant type (it is the simplest of the grant types)
$server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage));

// Add the "Authorization Code" grant type (this is where the oauth magic happens)
$server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage));

创建一个Token Controller [tonken.php] 目的是通过授权码获取access_token

// include our OAuth2 Server object
require_once __DIR__.'/server.php';

// Handle a request for an OAuth2.0 Access Token and send the response to the client
$server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();

oauth_clients插入一条记录,ps:像其他公司一般是需要申请审核在给插入记录的

INSERT INTO oauth_clients (client_id, client_secret, redirect_uri) VALUES ("testclient", "testpass", "http://fake/");

创建一个资源控制器resource.php 在拿到access_token后,进行资源请求

require_once __DIR__.'/server.php';

//echo file_put_contents("test.txt",json_encode($_POST));
//var_dump($_POST);die;
if(!$server->verifyResourceRequest(OAuth2\Request::createFromGlobals())){
    $server->getResponse()->send();
    die;
}


$token = $server->getAccessTokenData(OAuth2\Request::createFromGlobals());

授权页面,询问用户是否授权authorize.php

require_once __DIR__.'/server.php';

$request = OAuth2\Request::createFromGlobals();
$response = new OAuth2\Response();

// validate the authorize request
if (!$server->validateAuthorizeRequest($request, $response)) {
    $response->send();
    die;
}
// display an authorization form
if (empty($_POST)) {
  exit('
<form method="post">
  <label>Do You Authorize TestClient?</label><br />
  <input type="submit" name="authorized" value="yes">
  <input type="submit" name="authorized" value="no">
</form>');
}

// print the authorization code if the user has authorized your client
$is_authorized = ($_POST['authorized'] === 'yes');
$server->handleAuthorizeRequest($request, $response, $is_authorized);
<!--if ($is_authorized) {-->
<!--  // this is only here so that you get to see your code in the cURL request. Otherwise, we'd redirect back to the client-->
<!--  $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=')+5, 40);-->
<!--  exit("SUCCESS! Authorization Code: $code");-->
<!--}-->
$response->send();

api.php 获取用户授权码之后会进行一次回调,回调的内容,使用curl 进行post 请求

<?php


require_once __DIR__ . '/server.php';
//授权码是否为空
$code = empty($_GET['code']) ? '' : $_GET['code'];
//默认的参数
$config = array('client_id' => 'testclient', 'client_secret' => 'testpass');
$query = array(
    //授权类别
    'grant_type' => 'authorization_code',
    //授权码
    'code' => $code,
    'client_id' => $config['client_id'],
    'client_secret' => $config['client_secret'],
);
//模拟Post请求 请求access_token
$url = "http://127.0.0.1:8881/token.php";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($query));
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$output = curl_exec($ch);
curl_close($ch);
$res = json_decode($output, true);


//使用access_token 模拟post
$resource = array('access_token' => $res['access_token']);
$url = "http://127.0.0.1:8881/resource.php";
//$header = 'Content-Type:application/x-www-form-urlencoded';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
//must be http_build_query_build 将数组格式转为 url-encode模式
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($resource));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
$info = curl_getinfo($ch);
$output = curl_exec($ch);
curl_close($ch);
var_dump($info);
//var_dump($info1);

var_dump($output);

我们通过访问资源可获得user_id了,Oauth2过程也就结束了.谢谢~

转载于:https://my.oschina.net/kakoi/blog/885369

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QQ互联开发者必读 尊敬的QQ互联开发者: 您好,感谢您选择了PHP SDK 适用版本。 该版本运营环境:PHP + 数据库(可选) + MemCache(可选) PHP版本要求: PHP5.2 + (json_decode函数需要) 开启Curl模块:检查方式是 写一个 phpinfo();的测试文件,需要找到curl的描述方可有效。 如果选择数据库,需要开启mysql。(适用于中型网站) 如果选择MemCache,需要开启php_memcache 功能,同时需要Memcache的支持。(可用于大型网站) PHP SDK 操作流程: 在浏览器中,以网站的方式打开index.php(例如:http://www.example.com/index.php),首次将跳转到安装页面, 填好相关的APPID,APPKEY,选择对应的开放的API。选择session模式(系统支持三种,普通的session_start,基于数据库的session以及memcache的session,memcache的session支持需要MemCache的支持) 最后一个选项是debug功能,打开debug 功能,可以更加方面知道参数的传递地址,参数名称和数值以及结果的返回。 配置好了之后,点击确定,系统会验证相关的参数是否正确。值得注意的地方是:数据库会自动建立sessions表,sessions表的结构如下: CREATE TABLE if not exists `sessions` ( `sessionkey` varchar(32) NOT NULL, `sessionvalue` text NOT NULL, `sessionexpiry` datetime NOT NULL, `sessionip` varchar(15) DEFAULT NULL, PRIMARY KEY (`sessionkey`) ) DEFAULT CHARSET=utf8; 特别强调:在服务器运营环境中,请关闭debug功能。在配置选项完毕之后,删除install目录。在开发环境中,建议开启debug功能,这样,你可以很清晰的清楚传递的参数。 配置好了之后,系统会返回 index.php页面,你就可以开始 php sdk 的入门体验咯。 下面这些话是对coder说的: 代码结构采用api对应的目录,每个api对应相同文件名的PHP文件。代码中涉及到POST操作的部分,分为前后台,通过<?php if(isset($_POST)&&!empty($_POST)){ //这部分是POST处理的部分 //重点看这部分 //参数处理这里有点弱,没有做过多的判断,请在真实运营平台程序中加强 }else{ //这部分显示前台页面 } 每个API文件实现的基本思路是: $sUrl = ""; //指定API地址 $aGetParam = array(...); //指定GET参数 $aPOSTParam = array(...); //指定POST参数 $aFileParam = array(...); //指定文件上传的参数 $sContent = GET|POST|upload($sUrl,$aGETParam|$aPOSTParam,$aFileParam[upload的时候需要,其他时候无此参数]); If($sContent!==FALSE){ $aResult = json_decode($sContent,true); //转化成数组 ... //对数组的分析 } 下面对三个主要函数进行分析,文件位置在 common/function.php里面: GET函数: function get($sUrl,$aGetParam){ global $aConfig; //全局参数 $oCurl = curl_init(); //初始化curl if(stripos($sUrl,"https://")!==FALSE){ //对CURL对SSL的支持处理 curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE); } //拼接GET参数 $aGet = array(); foreach($aGetParam as $key=>$val){ $aGet[] = $key."=".urlencode($val); //注意此处的urlencode } curl_setopt($oCurl, CURLOPT_URL, $sUrl."?".join("&",$aGet));//设置访问URL curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );//设置调用返回 $sContent = curl_exec($oCurl);//执行访问 $aStatus = curl_getinfo($oCurl); //获取CURL的状态信息 curl_close($oCurl);//关闭CURL //系统自带的调试信息,运营环境可以删除这些调试信息 if(intval($aConfig["debug"])===1){ echo "<tr><td class='narrow-label'>请求地址:</td><td><pre>".$sUrl."</pre></td></tr>"; echo "<tr><td class='narrow-label'>GET参数:</td><td><pre>".var_export($aGetParam,true)."</pre></td></tr>"; echo "<tr><td class='narrow-label'>请求信息:</td><td><pre>".var_export($aStatus,true)."</pre></td></tr>"; if(intval($aStatus["http_code"])==200){ echo "<tr><td class='narrow-label'>返回结果:</td><td><pre>".$sContent."</pre></td></tr>"; if((@$aResult = json_decode($sContent,true))){ echo "<tr><td class='narrow-label'>结果集合解析:</td><td><pre>".var_export($aResult,true)."</pre></td></tr>"; } } } if(intval($aStatus["http_code"])==200){ //正常结果返回 return $sContent; //返回CURL获取到的内容 }else{ echo "返回出错:<pre>".$aStatus["http_code"].",请检查参数或者确实是腾讯服务器出错咯。</pre>"; //打印出错信息 return FALSE; //返回FALSE,注意在判断的时候,请用$sContent===FALSE 或者 $sContent!==FALSE 来判断 } } POST和upload 仅仅对不同的地方做说明: function post($sUrl,$aPOSTParam){ global $aConfig; ... //拼接POST数据 $aPOST = array(); foreach($aPOSTParam as $key=>$val){ $aPOST[] = $key."=".urlencode($val); } curl_setopt($oCurl, CURLOPT_URL, $sUrl); curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 ); //指定是POST curl_setopt($oCurl, CURLOPT_POST,true); curl_setopt($oCurl, CURLOPT_POSTFIELDS, join("&", $aPOST));//指定POST数据 $sContent = curl_exec($oCurl); $aStatus = curl_getinfo($oCurl); curl_close($oCurl); ...... } /* * 上传图片 */ function upload($sUrl,$aPOSTParam,$aFileParam){ ... //防止请求超时 set_time_limit(0); $oCurl = curl_init(); if(stripos($sUrl,"https://")!==FALSE){ curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false); } $aPOSTField = array(); foreach($aPOSTParam as $key=>$val){ $aPOSTField[$key]= $val; } foreach($aFileParam as $key=>$val){ $aPOSTField[$key] = "@".$val;);//文件路径,前面要加@,表明是文件上传 } curl_setopt($oCurl, CURLOPT_URL, $sUrl); curl_setopt($oCurl, CURLOPT_POST, true); curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 ); curl_setopt($oCurl, CURLOPT_POSTFIELDS, $aPOSTField); //这里也不同 $sContent = curl_exec($oCurl); $aStatus = curl_getinfo($oCurl); curl_close($oCurl); ... } 该PHP SDK 目前演示地址:http://www.172web.com/, 如果涉及到网站改版,具体演示地址见网站公告。 如有问题,请通过邮件咨询:admin@172web.com.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值