一、oauth的授权码模式
这里引用了阮一峰的oauth的文章的部分内容,传送门
步骤:
1、A.com向B.com请求获取授权码
2、B.com返回授权码给A.com
3、A.com用授权码向B.com获取令牌
4、B.com返回令牌给A.com
5、使用令牌获取数据资源
第一步,A 网站提供一个链接,用户点击后就会跳转到 B 网站,授权用户数据给 A 网站使用。下面就是 A 网站跳转 B 网站的一个示意链接。
https://b.com/oauth/authorize?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read
上面 URL 中,response_type参数表示要求返回授权码(code),client_id参数让 B 知道是谁在请求,redirect_uri参数是 B 接受或拒绝请求后的跳转网址,scope参数表示要求的授权范围(这里是只读)。执行成功后,B.com往数据库的oauth_authorization_codes写入对应数据
第二步,用户跳转后,B 网站会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回redirect_uri参数指定的网址。跳转时,会传回一个授权码,就像下面这样。
https://a.com/callback?code=AUTHORIZATION_CODE
上面 URL 中,code参数就是授权码。
第三步,A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。
https://b.com/oauth/token?
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=CALLBACK_URL
上面 URL 中,client_id参数和client_secret参数用来让 B 确认 A 的身份(client_secret参数是保密的,因此只能在后端发请求),grant_type参数的值是AUTHORIZATION_CODE,表示采用的授权方式是授权码,code参数是上一步拿到的授权码,redirect_uri参数是令牌颁发后的回调网址。
第四步,B 网站收到请求以后,就会颁发令牌。具体做法是向redirect_uri指定的网址,发送一段 JSON 数据。
{
"access_token":"ACCESS_TOKEN",
"token_type":"bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN",
"scope":"read",
"uid":100101,
"info":{...}
}
上面 JSON 数据中,access_token字段就是令牌,A 网站在后端拿到了。
二、开干
- 下载oauth-server-php:
git clone https://github.com/bshaffer/oauth2-server-php.git -b master
存放到根目录
2.安装数据库
执行以下sql语句:
--
-- Database: `oauth2db`
--
-- --------------------------------------------------------
--
-- 表的结构 `oauth_access_tokens`
--
CREATE TABLE IF NOT EXISTS `oauth_access_tokens` (
`access_token` varchar(40) NOT NULL,
`client_id` varchar(80) NOT NULL,
`user_id` varchar(255) DEFAULT NULL,
`expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`scope` varchar(2000) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- 表的结构 `oauth_authorization_codes`
--
CREATE TABLE IF NOT EXISTS `oauth_authorization_codes` (
`authorization_code` varchar(40) NOT NULL,
`client_id` varchar(80) NOT NULL,
`user_id` varchar(255) DEFAULT NULL,
`redirect_uri` varchar(2000) DEFAULT NULL,
`expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`scope` varchar(2000) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- 表的结构 `oauth_clients`
--
CREATE TABLE IF NOT EXISTS `oauth_clients` (
`client_id` varchar(80) NOT NULL,
`client_secret` varchar(80) NOT NULL,
`redirect_uri` varchar(2000) NOT NULL,
`grant_types` varchar(80) DEFAULT NULL,
`scope` varchar(100) DEFAULT NULL,
`user_id` varchar(80) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- 转存表中的数据 `oauth_clients`
--
INSERT INTO `oauth_clients` (`client_id`, `client_secret`, `redirect_uri`, `grant_types`, `scope`, `user_id`) VALUES
('testclient', 'testpass', 'https://user.endv.cn/', 'authorization_code', '', '');
-- --------------------------------------------------------
--
-- 表的结构 `oauth_jwt`
--
CREATE TABLE IF NOT EXISTS `oauth_jwt` (
`client_id` varchar(80) NOT NULL,
`subject` varchar(80) DEFAULT NULL,
`public_key` varchar(2000) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- 表的结构 `oauth_refresh_tokens`
--
CREATE TABLE IF NOT EXISTS `oauth_refresh_tokens` (
`refresh_token` varchar(40) NOT NULL,
`client_id` varchar(80) NOT NULL,
`user_id` varchar(255) DEFAULT NULL,
`expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`scope` varchar(2000) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- 表的结构 `oauth_scopes`
--
CREATE TABLE IF NOT EXISTS `oauth_scopes` (
`scope` text,
`is_default` tinyint(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- 表的结构 `oauth_users`
--
CREATE TABLE IF NOT EXISTS `oauth_users` (
`username` varchar(255) NOT NULL,
`password` varchar(2000) DEFAULT NULL,
`first_name` varchar(255) DEFAULT NULL,
`last_name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3、写入数据到数据库
添加客户端到表:oauth_clients,只有添加到该表到客户端才可以获取授权码
+------------+---------------+-------------------+--------------------+-------+---------+
| client_id | client_secret | redirect_uri | grant_types | scope | user_id |
+------------+---------------+-------------------+--------------------+-------+---------+
| testclient | testpass | http://127.0.0.1/ | authorization_code | | |
+------------+---------------+-------------------+--------------------+-------+---------+
4、配置server服务
在根目录新建server.php文件,代码如下:
<?php
/** 配置 */
$dsn= 'mysql:dbname=test;host=localhost';
$username = 'test';
$password = 'test';
// 错误报告(这毕竟是一个演示!)
ini_set('display_errors',1);error_reporting(E_ALL);
// 自动加载
require_once('oauth2-server-php/src/OAuth2/Autoloader.php');
OAuth2\Autoloader::register();
$storage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));
// 通过存储对象或对象数组存储的oauth2服务器类
$server = new OAuth2\Server($storage);
// 授权码 有效期只有30秒
$server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage));
// 客户端证书
$server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage));
// 用户凭据
$server->addGrantType(new OAuth2\GrantType\UserCredentials($storage));
// 刷新令牌 启用这个会报错,原因未知
// $server->addGrantType(new OAuth2\GrantType\RefreshToken($refreshStorage))
注意:数据库的配置信息根据自己的配置进行操作
5、获取授权码
参考oauth的授权码模式的使用的第一步。A网站向B网站请求授权码,B网站生成授权码并写入表oauth_authorization_codes中,然后返回给A网站
6、使用授权码获取令牌
创建token.php文件,代码如下:
<?php
// include our OAuth2 Server object
require_once __DIR__.'/server.php';
$server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();
然后执行指令:
curl -u testclient:testpass http://127.0.0.1/token.php --data "grant_type=authorization_code&code=你的授权码"
执行成功后则会返回数据:
{"access_token":"84c66d296308aad20aa5e065743d2fe30426b046","expires_in":3600,"token_type":"Bearer","scope":null,"refresh_token":"d49cd4d7d875065888fc457c7c714cab9fcf9d69"}
7、使用token获取数据
创建resource.php文件,代码如下:
<?php
//资源控制器的建立和测试
require_once __DIR__.'/server.php';
if (!$server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) {
$server->getResponse()->send();
die;
}
$token = $server->getAccessTokenData(OAuth2\Request::createFromGlobals());
echo "User ID associated with this token is {$token['user_id']}";
echo json_encode(array('success' => true, 'message' => '您访问了我的API!'));
执行指令:
curl https://127.0.0.1/resource.php --data 'access_token=YOUR_TOKEN'
在这个resource.php文件中可以根据token的正确性来决定是否返回相应的数据给请求方。
以上仅供参考,如有错误,望各位指正。