前奏
系统:Ubuntu
语言:PHP7
框架:YAF
OAuth2.0:bshaffer/oauth2-server-php
OAuth2.0
有很多开源代码库
Github 排名前两位
thephpleague/oauth2-server
bshaffer/oauth2-server-php
本文使用的是第二个:bshaffer
。原因:使用简单,可以很快上手,文档齐全,功能完善。
wiki
: https://bshaffer.github.io/oa...github
: https://github.com/bshaffer/o...
引入 OAuth2.0 的 Server 端源代码
编辑 Composer.json
文件
{
"require": {
"bshaffer/oauth2-server-php" : "v1.10.0"
}
}
yaf框架结构
├── application
│ └── modules
│ └── User
│ ├── controllers
│ │ └── Oauth.php
│ └── views
│ └── oauth
│ ├── authorize.php
│ ├── auth.php
│ ├── index.php
│ └── resource.php
├── Bootstrap.php
├── cli
├── composer.json
├── composer.lock
├── composer.phar
├── conf
├── docs
├── public
└── vendor
Yaf 框架中,在 Bootstrap.php
文件中自动加载 OAuth2.0
public function _initLoader(Yaf_Dispatcher $dispatcher)
{
include(APP_PATH . '/vendor/autoload.php');
}
新建一个 Controller 文件:Oauth.php
,在里面建立几个 Action
AuthorizeAction() 服务端:提供授权
TokenAction() 服务端:提供Token
ResourceAction() 服务端:提供资源
IndexAction() 客户端:模拟第三方接入
_server() 服务端:初始化服务器相关,如:存储,这里采用mysql
命名空间
use OAuth2\Server;
use OAuth2\Storage\Pdo;
use OAuth2\GrantType\AuthorizationCode;
use OAuth2\GrantType\ClientCredentials;
use OAuth2\GrantType\UserCredentials;
use OAuth2\Request;
use OAuth2\Response;
_server() 函数代码
private function _server()
{
$dbParams = array(
'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=oauth;charset=utf8;',
'username' => 'root',
'password' => '123456',
);
// $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost"
$storage = new Pdo($dbParams);
// Pass a storage object or array of storage objects to the OAuth2 server class
$server = new Server($storage);
// Add the "Client Credentials" grant type (it is the simplest of the grant types)
$server->addGrantType(new ClientCredentials($storage));
// Add the "Authorization Code" grant type (this is where the oauth magic happens)
$server->addGrantType(new AuthorizationCode($storage));
return $server;
}
IndexAction() 代码
public function indexAction()
{
$uri = $_SERVER['QUERY_STRING'];
$code = substr($uri, strpos($uri, 'code=')+5, 40);
$state = substr($uri, strpos($uri, 'state=')+6);
if ($code) {
$params = array(
'code' => $code,
'state' => $state,
'client_id' => 'client_id',
'client_secret' => 'client_secret',
'grant_type' => 'authorization_code',
'scope' => 'basic',
'redirect_uri' => 'http://yourhost/user/oauth/index',
);
$url = 'http://yourhost/user/oauth/token';
$result = $this->httpPost($url, $params);
$result = json_decode($result, true);
//写入Session,便于测试
Yaf_Session::getInstance()->set('access_token',$result['access_token']);
return false;
} else {
//客户端请求授权之前,页面中展示一个链接,用户点后,可以跳转至服务端的授权页面。
$this->getView()->assign('data', array())->render('oauth/index.php');
}
}
对应的模板代码:oauth/index.php
<div>
<a href="http://yourhost/User/Oauth/Authorize?response_type=code&client_id=client_id&redirect_uri=http://yourhost/user/oauth/index&scope=basic&state=xxx">click here</a>
</div>
AuthorizeAction() 代码
/**
* 展示授权页面,用户可以点击同意进行授权
*/
public function AuthorizeAction()
{
$request = Request::createFromGlobals();
$is_authorized = $request->request('is_authorized') ? true : false;
//判断用户是否同意授权
if ($is_authorized) {
$response = new Response();
$server = $this->_server();
// validate the authorize request
if (!$server->validateAuthorizeRequest($request, $response)) {
$response->send();
die;
}
$server->handleAuthorizeRequest($request, $response, $is_authorized)->send();
return false;
}
//将请求授权中带来的各个参数,写入授权页中的变量,用以授权表单POST提交。
$renderData = $_GET;
$this->getView()->assign('data', $renderData)->render('oauth/authorize.php');
}
用户授权页面:oauth/authorize.php
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>直达天庭 - 南天门</title>
<link type="text/css" href="http://api.weibo.com/oauth2/css/oauthV3/oauth_web.css?version=20140625" rel="stylesheet"/>
</head>
<body class="WB_UIbody WB_widgets">
<div class="WB_xline1 oauth_xline" id="outer">
<div class="oauth_wrap">
<div class="oauth_header clearfix">
<h1 class="WB_logo" title="微博"><a href="http://yourhost">天庭</a></h1>
<p class="login_account">
<span class="account_name">哪吒</span>
<span class="vline">|</span><a href="http://yourhost/user/oauth/list" target="_blank">我的应用</a></span>
</p>
</div>
<!-- 带头像 -->
<div class="WB_panel oauth_main">
<form id="authZForm" name="authZForm" action="/user/oauth/authorize" method="post" node-type="form">
<div class="oauth_content">
<div class="oauth_main_content clearfix">
<div class="app_info clearfix">
<div class="app_info_main clearfix">
<div class="app_icon">
<img class="app_img"
src="https://upload.api.weibo.com/square/aa397b7fgw1f556jk3z3bj20280283yc.jpg"
alt="app">
</div>
<div class="app_intro">
<h3><a href="http://app.weibo.com/t/feed/324Mrt" target="_blank">人间</a></h3>
<div class="app_des">凡人</div>
</div>
</div>
<div class="app_info_plus">
<div class="plus_tit">
http://app.weibo.com/t/feed/324Mrt<br/>有 1 个你关注的人连接
</div>
<div class="app_user_list">
<ul class="clearfix">
</ul>
</div>
</div>
</div>
<div class="oauth_info clearfix">
<div class="oauth_list">
<div class="list_tit">将允许<a href="http://app.weibo.com/t/feed/324Mrt" target="_blank">人间</a>进行以下操作:
</div>
<ul class="do_list">
<li>
<i class="icon_user"></i>获得你的个人信息,好友关系
</li>
<li>
<i class="icon_rss"></i>分享内容到你的微博
</li>
<li>
<i class="icon_comm"></i>获得你的评论
</li>
</ul>
</div>
</div>
</div>
<!-- 登录 -->
<div class="oauth_login_box01 clearfix">
<input type="hidden" name="scope" id="scope" value="<?php echo $data['scope'];?>"/>
<input type="hidden" name="response_type" value="<?php echo $data['response_type'];?>"/>
<input type="hidden" name="redirect_uri" value="<?php echo $data['redirect_uri'];?>"/>
<input type="hidden" name="client_id" value="<?php echo $data['client_id'];?>"/>
<input type="hidden" name="state" value="<?php echo $data['state'];?>"/>
<input type="hidden" name="is_authorized" value="1"/>
<input type="hidden" name="grant_type" value="<?php echo $data['grant_type'];?>"/>
<!-- </form> -->
<div class="oauth_login_submit">
<p class="oauth_formbtn"><a node-type="submit" href="#" onclick="return false;"
action-type="submit"
class="WB_btn_link formbtn_01"></a><a
node-type="cancel" href="javascript:;" action-type="cancel"
class="WB_btn_cancel"></a></p>
</div>
</div>
</div>
</form>
<!-- /登录 -->
</div>
</div>
</div>
</body>
</html>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$(".WB_btn_link").click(function(){
$("#authZForm").submit();
});
})
</script>
TokenAction()
/**
* 返回JSON结构数据
* {
access_token: "977b1077556e9b23ff07ef7606a5eaf947f27d41",
expires_in: 3600,
token_type: "Bearer",
scope: "basic",
refresh_token: "d2367887bdd743121adfe5fda5083064439f1cb1"
}
*/
public function TokenAction()
{
$server = $this->_server();
$server->handleTokenRequest(Request::createFromGlobals())->send();
return false;
}
ResourceAction() 代码
public function ResourceAction()
{
$server = $this->_server();
//获取授权用户Session中保存的access_token,用access_token可以请求权限范围内的所有接口
$_POST['access_token'] = Yaf_Session::getInstance()->get('access_token');
// Handle a request to a resource and authenticate the access token
if (!$server->verifyResourceRequest(Request::createFromGlobals())) {
$server->getResponse()->send();
die;
}
echo json_encode(array('success' => true, 'message' => 'You accessed my APIs!'));
return false;
}
请求用户资源:/user/oauth/resource
{
success: true,
message: "You accessed my APIs!"
}
实现思路:
- URL请求:/user/oauth/index,
Client端
对应的模板里放置一个链接,用以跳转至服务端的授权认证页面/user/oauth/authorize。授权成功后,服务端会将对应的code和state参数,附在回调的redirect_uri里,即:/user/oauth/index?code=fcd6a9589e7ab43398e4e5349b23846babc79fab&state=xxx,在indexAction中解析出回调的code,用以请求接口/user/oauth/token,来交换access_token。
- URL请求:/user/oauth/authorize,
Server端
对应的模板里是告知用户,即将授予的权限列表,以及是否允许授权的按钮。 - URL请求:/user/oauth/token,
Server端
获取access_token。 - URL请求:/user/oauth/resource,
Server端
获取用户资源
LAST:
- 各种授权类型,都可以很方便支持。
- 数据存储层,也可以随意切换,比如切换为
Redis
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。