http://www.rollosay.com/it/%E4%BD%BF%E7%94%A8OAuth-Server-PHP%E5%AE%9E%E7%8E%B0OAuth2%E6%9C%8D%E5%8A%A1php
在如今的網絡服務中,OAuth2.0服務已經很廣泛了,不管是facebook或者微博的第三方登陸,仍是手機APP登陸,都有很普遍的應用。
它主要的目的以下:
若是用戶的照片在A網站,他想要在B網站使用A網站的頭像,並不須要向B網站提供本身在A網站的用戶名和密碼,而直接給B一個Access Token來獲取A站的照片
具體流程以下:
1)用戶訪問網站B
2)B須要驗證用戶的身份
3)B將用戶定向到A網站,用戶輸入賬號密碼登陸A網站
4)A網站詢問是否要將Authentication的權利給B網站
5)用戶告訴A站能夠將認證權給B站
6)A網站把Authorization Code發給B站
7)B站用Autorization Code向A站換取Access Token
8)當B站擁有Access Token時,就擁有了用戶在A站的一些訪問權限
這是典型的Authorization Code Grant,經常運用於網絡應用之中css
還有Implicit Grant認證方式,這個則省去了Auth Code,開放平臺直接返回access_token和有效期,用戶ID等數據
這種常常運用於手機客戶端或者瀏覽器插件等沒有在線服務器的應用python
最後一種是Resource Owner Password Credentials Grant
這種是直接在應用中輸入賬號密碼,而後由應用XAuth技術將其提交給開放平臺並獲得Access Token
它常常用於PC可執行程序和手機應用,但因爲存在一些爭議,開發難度也較大,這裏我就先不討論他mysql
你能夠在github上下載OAuth Server PHP,也能夠用下列命令下載,不過內容都是同樣的git
1
2
3
|
mkdir
my-oauth2-walkthrough
cd my-oauth2-walkthrough
git
clone
https:
//github.com/bshaffer/oauth2-server-php.git -b master
|
在這以後配置數據庫github
1
2
3
4
5
6
7
|
CREATE TABLE oauth_clients (client_id VARCHAR(
80
) NOT NULL, client_secret VARCHAR(
80
) NOT NULL, 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));
|
咱們來創建一個server.php文件來配置server,這個文件能夠被全部的終端來調用。看require once就知道這個文件是平級的。sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
$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
));
|
最後記得配置數據庫PDO的用戶名和密碼數據庫
下面,咱們將創建一個Token控制器,這個控制器URI將會返回OAuth2的Token給客戶端json
1
2
3
4
5
|
// 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();
|
須要先建立一條記錄,來註冊一個新的應用瀏覽器
1
|
INSERT INTO oauth_clients (client_id, client_secret, redirect_uri) VALUES (
"testclient"
,
"testpass"
,
"http://fake/"
);
|
而後用命令行調用
1
|
curl -u testclient:testpass http:
//localhost/token.php -d 'grant_type=client_credentials'
|
這裏的URL只是示例,實地操做要肯定能找到這個token.php
若是運行正常,則顯示
1
|
{
"access_token"
:
"03807cb390319329bdf6c777d4dfae9c0d3b3c35"
,
"expires_in"
:3600,
"token_type"
:
"bearer"
,
"scope"
:
null
}
|
你建立了Token,你須要在API中測試它,因而你寫了以下代碼
1
2
3
4
5
6
7
8
9
|
// 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
if
(!
$server
->verifyResourceRequest(OAuth2\Request::createFromGlobals())) {
$server
->getResponse()->send();
die
;
}
echo
json_encode(
array
(
'success'
=> true,
'message'
=>
'You accessed my APIs!'
));
|
而後運行下面的命令,記得將YOUR_TOKEN替換成剛纔獲得的token,還有確保URL的正確
1
|
curl http:
//localhost/resource.php -d 'access_token=YOUR_TOKEN'
|
若是沒出問題,則會獲得下面的結果
1
|
{
"success"
:
true
,
"message"
:
"You accessed my APIs!"
}
|
驗證控制器是OAuth2的殺手鐗,它容許你的平臺幫助用戶驗證第三方應用
它不像第一個例子中直接返回一個Access Token,這裏稍微複雜一點
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
// include our OAuth2 Server object
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();
|
而後在瀏覽器中打開這個URL
1
|
|
你將會看到一個表單,當你選擇yes的時候會彈出你所得到的Authorization Code
如今你能夠用這個Authorization Code來剛纔創建的token.php得到TOKEN,命令以下
1
|
curl -u testclient:testpass http:
//localhost/token.php -d 'grant_type=authorization_code&code=YOUR_CODE'
|
就像剛纔同樣,你得到了一個TOKEN
1
|
{
"access_token"
:
"6f05ad622a3d32a5a81aee5d73a5826adb8cbf63"
,
"expires_in"
:3600,
"token_type"
:
"bearer"
,
"scope"
:
null
}
|
請在30秒內完成這個操做,由於Authorization Code的有效期只有30秒
當你認證了一個用戶而且分派了一個Token以後,你可能想知道彼時究竟是哪一個用戶使用了這個Token
你可使用handleAuthorizeRequest的可選參數user_id來完成,修改你的authorize.php文件
1
2
|
$userid
= 1234;
// A value on your server that identifies the user
$server
->handleAuthorizeRequest(
$request
,
$response
,
$is_authorized
,
$userid
);
|
這樣一來,用戶ID就伴隨Token一塊兒存進數據庫了
當Token被客戶端使用的時候,你就知道是哪一個用戶了,修改resource.php來完成任務
1
2
3
4
5
6
7
|
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']}"
;
|
經過閱讀這篇文章體會:
1、其實像新浪微博,QQ都是用了第二種方法Authorization Code,跳到受權頁面,用戶登陸而後,
執行$server
->handleAuthorizeRequest(
$request
,
$response
,
$is_authorized
,
$userid
);把用戶ID和token綁定起來,其實我有個疑問,爲何如今不直接把token返回給B站了,還要先返回code,而後再用code去請求token了,
curl -u testclient:testpass http:
//localhost/token.php -d 'grant_type=client_credentials'
,這種的做用其實就是直接驗證一下客戶端是否是受權的客戶端,其實感受意義不大,若是源代碼被人看了
-u testclient:testpass
直接就知道了,可是好處就是根據token令牌綁定用戶ID,下次請求接口直接帶參數token,就能夠判斷用戶,並傳回相應的信息。