什么是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
过程也就结束了.谢谢~