基于thinkphp5.1框架搭建OAuth2.0服務端

OAuth是用于服務端與客戶端授權登錄的協議,OAuth2.0是OAuth的第二個版本,關于OAuth2.0的基礎知識,可以閱讀阮一峰的一篇博文,對OAuth2.0的介紹非常詳細,只要理解了OAuth2.0的授權過程,在自己網站實現OAuth2.0并不復雜。

本文將講解如何基于thinkphp5.1的框架實現OAuth2.0的服務端。

1 環境搭建

首先確保你已經搭建好了服務器,并且已經能夠正常訪問你的服務器。我的環境Xampp+thinkphp5.1.

2 安裝OAuth2.0 php包

你頁根據OAuth2.0的協議自己去實現代碼,但是最快捷最安全最可靠的方法當然是移植第三方OAuth2.0包。OAuth官網提供了很多第三方包,詳見網站https://oauth.net/code/, 如下圖,因為thinkphp是基于php語言,因此我選擇了PHP下第一個。

點擊PHP OAuth2 Server會跳入源碼下載庫,將其下載到電腦即可。

下載后解壓,我們只需要將里面/src/OAuth文件夾整個拷貝到tp5/extend/目錄下,就可以自動注冊對應的命名空間。之后我們就可以使用\OAuth2\...的方式去使用OAuth里面的任何方法。

3 實現OAuth服務端

3.1 創建數據庫

由于我們之前下載的OAuth包有用到很多數據表,所以需要按照其要求創建好數據表,創建代碼如下:

CREATE TABLE oauth_clients (

? client_id? ? ? ? ? ? VARCHAR(80)? NOT NULL,

? client_secret? ? ? ? VARCHAR(80),

? redirect_uri? ? ? ? ? VARCHAR(2000),

? grant_types? ? ? ? ? VARCHAR(80),

? scope? ? ? ? ? ? ? ? VARCHAR(4000),

? user_id? ? ? ? ? ? ? VARCHAR(80),

? PRIMARY KEY (client_id)

);

CREATE TABLE oauth_access_tokens (

? access_token? ? ? ? VARCHAR(40)? ? NOT NULL,

? client_id? ? ? ? ? ? VARCHAR(80)? ? NOT NULL,

? user_id? ? ? ? ? ? ? VARCHAR(80),

? expires? ? ? ? ? ? ? TIMESTAMP? ? ? NOT NULL,

? scope? ? ? ? ? ? ? ? VARCHAR(4000),

? PRIMARY KEY (access_token)

);

CREATE TABLE oauth_authorization_codes (

? authorization_code? VARCHAR(40)? ? NOT NULL,

? client_id? ? ? ? ? VARCHAR(80)? ? NOT NULL,

? user_id? ? ? ? ? ? VARCHAR(80),

? redirect_uri? ? ? ? VARCHAR(2000),

? expires? ? ? ? ? ? TIMESTAMP? ? ? NOT NULL,

? scope? ? ? ? ? ? ? VARCHAR(4000),

? id_token? ? ? ? ? ? VARCHAR(1000),

? PRIMARY KEY (authorization_code)

);

CREATE TABLE oauth_refresh_tokens (

? refresh_token? ? ? VARCHAR(40)? ? NOT NULL,

? client_id? ? ? ? ? VARCHAR(80)? ? NOT NULL,

? user_id? ? ? ? ? ? VARCHAR(80),

? expires? ? ? ? ? ? TIMESTAMP? ? ? NOT NULL,

? scope? ? ? ? ? ? ? VARCHAR(4000),

? PRIMARY KEY (refresh_token)

);

CREATE TABLE oauth_users (

? username? ? ? ? ? ? VARCHAR(80),

? password? ? ? ? ? ? VARCHAR(80),

? first_name? ? ? ? ? VARCHAR(80),

? last_name? ? ? ? ? VARCHAR(80),

? email? ? ? ? ? ? ? VARCHAR(80),

? email_verified? ? ? BOOLEAN,

? scope? ? ? ? ? ? ? VARCHAR(4000)

);

CREATE TABLE oauth_scopes (

? scope? ? ? ? ? ? ? VARCHAR(80)? ? NOT NULL,

? is_default? ? ? ? ? BOOLEAN,

? PRIMARY KEY (scope)

);

CREATE TABLE oauth_jwt (

? client_id? ? ? ? ? VARCHAR(80)? ? NOT NULL,

? subject? ? ? ? ? ? VARCHAR(80),

? public_key? ? ? ? ? VARCHAR(2000)? NOT NULL

);

3.2 創建控制器

需要在tp5/application/index/controller下創建一個控制器,命名為OAuth.php,寫入以下代碼,控制器就創建完成了。

<?php

namespace app\index\controller;

class OAuth extends \think\Controller

{

}

3.3 實現authorize

OAuth 2.0的運行流程如下圖。

所以第一步是實現authorization。

我們在之前創建好的控制器中添加一個函數authorize()

代碼如下(注意,dbname需要換成你自己的數據庫的名字,下同):

<?php

namespace app\index\controller;

class OAuth extends \think\Controller

{

? ? public function authorize()

? ? {

? ? ? ? global $server;

? ? ? ? $dsn? ? ? = 'mysql:dbname=XXX;host=127.0.0.1';

? ? ? ? $username = 'root';

? ? ? ? $password = '';

? ? ? ? \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));

? ? ? ? $request = \OAuth2\Request::createFromGlobals();

? ? ? ? $response = new \OAuth2\Response();

? ? ? ? // validate the authorize request

? ? ? ? if (!$server->validateAuthorizeRequest($request, $response)) {

? ? ? ? ? ? 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();

? ? }

}

在tp5/route/route.php中創建相應路由,post方法和get方法都創建

Route::get('authorize', 'OAuth/authorize');

Route::post('authorize', 'OAuth/authorize');

接下來驗證創建的authorize是否成功,通過以下鏈接去訪問,在瀏覽器中輸入以下鏈接,回車后就會顯示一個驗證表單,當你點擊yes按鈕后,如果窗口顯示一串字符,那么就表示authorize創建成功了,這串字符就是code,接下來需要通過這個code去獲取token。

http://localhost/authorize.php?response_type=code&client_id=testclient&state=xyz

3.4 實現token申請方法

在OAuth.php控制器中添加函數token(),代碼如下

public function token(){

? ? ? ? global $server;

? ? ? ? $dsn? ? ? = 'mysql:dbname=XXX;host=127.0.0.1';

? ? ? ? $username = 'root';

? ? ? ? $password = '';

? ? ? ? \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));


? ? ? ? // Handle a request for an OAuth2.0 Access Token and send the response to the client

? ? ? ? $server->handleTokenRequest(\OAuth2\Request::createFromGlobals())->send();?

? ? }

在tp5/route/route.php中創建相應路由,post方法和get方法都創建

Route::get('token', 'OAuth/token');

Route::post('token', 'OAuth/token');

在測試是否獲取token之前,我們需要在oauth_clients表中加一條數據,可執行如下SQL:

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

接下來從CMD運行以下內容,注意:code的值需要換成你上一步生成的code

curl -u testclient:testpass http://localhost/token.php -d 'grant_type=authorization_code&code=YOUR_CODE'

如果成功的話,你應該會得到access token,如下內容

{"access_token":"6f05ad622a3d32a5a81aee5d73a5826adb8cbf63","expires_in":3600,"token_type":"bearer","scope":null}

3.5 實現Resource獲取

在OAuth.php控制器中添加函數resource(),代碼如下

public function resource()

? ? {

? ? ? ? // include our OAuth2 Server object

? ? ? ? global $server;

? ? ? ? $dsn? ? ? = 'mysql:dbname=XXX;host=127.0.0.1';

? ? ? ? $username = 'root';

? ? ? ? $password = '';

? ? ? ? \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));

? ? ? ? // Handle a request to a resource and authenticate the access token

? ? ? ? if (!$server->verifyResourceRequest(\OAuth2\Request::createFromGlobals())) {

? ? ? ? ? ? $server->getResponse()->send();

? ? ? ? ? ? die;

? ? ? ? }

? ? ? ? echo json_encode(array('success' => true, 'message' => 'You accessed my APIs!'));

? ? }

在tp5/route/route.php中創建相應路由,post方法和get方法都創建

Route::get('resource', 'OAuth/resource');

Route::post('resource', 'OAuth/resource');

驗證:通過CMD運行以下內容(將access token的值換成上一次獲取的access token):

curl http://localhost/resource.php -d 'access_token=YOUR_TOKEN'

如果成功,將會獲得以下響應:

{"success":true,"message":"You accessed my APIs!"}

4 總結

至此,OAuth所有相關的都實現了,整個過程就是客戶端去想服務端申請token,然后拿著這個token向服務端獲取資源的過程。后續有什么不明白的地方,大家可以在下面評論,我有時間會回答大家。關于oauth2-server-php庫的更多詳情,大家可以訪問http://bshaffer.github.io/oauth2-server-php-docs/。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容