iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 18
1
Modern Web

使用 Laravel 打造 RESTful API系列 第 18

OAuth2 認證機制 Token 原理

使用Laravel 8 PHP主流框架打造RESTful API(iT邦幫忙鐵人賽系列書)ISBN:9789864345304

本系列文章已集結成冊與鐵人賽文章差異內容,有以下幾點:

更新至Laravel 8、基礎的PHP重點筆記、加強製作API流程細節、加入程式設計模式,優化、重構程式碼的部分,並且於書籍前面的章節介紹Git。

讓您從製作第一個簡單的API到優化自己的程式碼,分享我的經驗給您,打造自己的最強大腦API,若有興趣的朋友可以參考看看

天瓏網路書局:
https://www.tenlong.com.tw/products/9789864345304


此篇文章同步發於個人部落格

簡單說要做任何需要認證的請求時。例如(我「想」要新增動物)那麼就要先跟伺服器請求核發一組 Access Token(就是一段亂碼),把這個 Token 附帶在請求中,就可以操作需要驗證的API (我要新增動物-附帶有效的Token)

Passport 是一個 Laravel 官方推薦的套件,可以輕鬆簡單的讓你完成一個完善的 OAuth2 認證機制!

(這裡指的是否登入的感覺,不是權限角色的分組)

順帶一提,Passport Laravel版本必須要大於 5.3 才能使用。

有四種不同的授權類型

  • 密碼授權
  • 授權碼授權
  • 個人授權
  • 同步授權

密碼授權

如果公司自己有手機app或其他產品,會用到 API 那就可以用密碼授權!這是最簡單的一種,但這種方法比較少見,可能過程中要輸入帳號密碼,相對來說比較有風險。

使用者再請求 Token 的時候必須附帶資料如下

  'grant_type' => 'password', //告訴伺服器密碼授權
  'client_id' => '2', // 伺服器端會有一筆client ID資料,在安裝Passport 有新增一組或日後依需求新增。
  'client_secret' => 'tXGMPZpKOlv3qkjrCPBeokueJN8mwaT7K8yAnbYE',  //那個ID對應的 secret 值
  'username' => 'victor@2020ironman.demo.com', // 登入哪個使用者
  'password' => '123456789', //密碼
  'scope' => '', //作用區(如果有時間再解釋這個部分)

回傳

{
    "token_type": "Bearer",
    "expires_in": 1295999,
    "access_token": "eyJ0eXAi...",
    "refresh_token": "def5020..."
}

表示授權成功!可以利用這一個 access_token 來請求操作需要驗證的API。

這是請求 Token 方式,但我們的系統中還未設定 Animal 資源還有 Type 資源 必須驗證才能操作。

設定操作資源需驗證的方法

AnimalController、TypeController 皆加入 __construct()

public function __construct()
{
    $this->middleware('auth:api', ['except' => ['index','show']]);
}

除了 index (查詢清單) 、 show (查詢單一資源) 不需要驗證其他必需認證才可以操作。

接下來開啟 Postman 送一次新增動物的請求。

POST api/animal

請求未認證的錯誤

因為我們沒有附上 access_token 所以請求失敗 狀態碼 401 未認證。

使用 Postman 取的 access_token 方法

POST /oauth/token HTTP/1.1
Content-type: application/x-www-form-urlencoded

成功請求Token

access_token 複製下來,並且回到請求新增動物的畫面,貼到 Headers 再請求一次新增動物的 API

成功新增動物

成功!

如果出現如下方圖片錯誤請清除快取再嘗試一試看看!

快取未清除產生的錯誤

清除快取

php artisan config:cache
參數 說明
access_token 操作需要驗證的資源時要提供給API伺服器驗證的東西
refresh_token 如果你有設定access_token過期時間的話,可以用這個 Token 來請求新的 access_token
expires_in access_token 還有多久過期

自訂 Token 過期時間

Passport 預設 Token 核發後一年過期,如果想要自訂有效時間,請依照下方程式碼修改

AuthServiceProvider

public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    // access_token 設定核發後15天後過期
    Passport::tokensExpireIn(now()->addDays(15));
    
    // refresh_token 設定核發後30天後過期
    Passport::refreshTokensExpireIn(now()->addDays(30));
}

刷新 access_token

時間越短安全性越高,如密碼授權的方式,不斷的發送請求內容還包含 帳號密碼 也會增加 安全上的疑慮。

可以利用 refresh_token 來刷新 access_token 只要 refresh_token 還沒過期的話都可以刷新access_token

POST /oauth/token
{
    "grant_type" : "refresh_token",
    "refresh_token" : "the-refresh-token",
    "client_id" : "client-id",
    "client_secret" : "client-secret",
    "scope" : ""
}

回傳

{
    "token_type": "Bearer",
    "expires_in": 1296000,
    "access_token": "eyJ0eX...",
    "refresh_token": "def502..."
}

回傳一組新的授權資料!


上一篇
Laravel 安裝 Passport 身分驗證
下一篇
修改資料表新建 migration
系列文
使用 Laravel 打造 RESTful API30

2 則留言

0
aa4731073
iT邦新手 5 級 ‧ 2021-07-06 16:34:16

大大你好,請問一下,今天假如我把專案建在公司的伺服器上面,那我要怎麼設定Postman的參數來拿到Login的access_token?
※我有買你的書支持一下,但因為書還沒來又剛好專案卡在這,不知道怎麼設定postman參數來測試我的程式。還希望您能幫我解答,謝謝大大。

看更多先前的回應...收起先前的回應...
aa4731073 iT邦新手 5 級 ‧ 2021-07-06 16:39:41 檢舉

https://www.itread01.com/content/1544969530.html

我有找到這個資料,但不確定他的登入帳號密碼是指甚麼,是指登入伺服器的帳密嗎?還是資料庫面的會員帳密?

Victor iT邦新手 3 級 ‧ 2021-07-06 16:54:30 檢舉

您好!感謝您的支持,書裡面有另外說明其他的授權流程,這篇文章使用的方式是 密碼授權 的流程來取得 access_token

使用 POST 方式並且使用貴公司架設該伺服器的網域,後面接上/oauth/token

http://127.0.0.1/oauth/token

(修改請求的網址)

https://[修改為貴公司的網域]/oauth/token

Postman body 的頁籤中 點選 x-www-form-urlencoded 然後將以下內容填寫於表單中。

KEY => VALUE //說明(可不用填入)

 'grant_type' => 'password', //告訴伺服器密碼授權
  'client_id' => '2', // 伺服器端會有一筆client ID資料,在安裝Passport 有新增一組或日後依需求新增。
  'client_secret' => 'tXGMPZpKOlv3qkjrCPBeokueJN8mwaT7K8yAnbYE',  //那個ID對應的 secret 值
  'username' => 'victor@2020ironman.demo.com', // 登入哪個使用者
  'password' => '123456789', //該使用者的密碼
  'scope' => '',

值(VALUE)的部分請替換為您伺服器產生的 client_id client_secret

username password 是會員的帳號,假設這個 access_token 以後始要用來代表 會員1 (假設 帳號:user1、密碼:password1)如果這樣的話請帶入

username : user1
password : password1

就可以得到代表 會員(user1)的 access_token

aa4731073 iT邦新手 5 級 ‧ 2021-07-07 14:46:04 檢舉

我按照大大的方法去試過了,但Http狀態碼會顯示405而失敗

Victor iT邦新手 3 級 ‧ 2021-07-07 23:47:15 檢舉

第一種可能,可能沒有正確設定專案中的 Route,沒有 POST /oauth/token 的路由

在專案資料夾中執行以下指令,確認一下有沒有 /oauth/token 網址,並且是 POST 方法的內容。

php artisan route:list

如果有照理來說應該要有辦法取的 token


第二種有可能伺服器沒有設定允許 POST 方法,有可能只允許 GETHEAD ,如果專案在電腦本機上可以運行,能請求到Token 或許是伺服器沒有設定好的問題。

以上目前想到的兩種可能提供給您參考。

0
fred3571588
iT邦新手 5 級 ‧ 2021-10-27 13:55:49

請問我在上面執行新增動物請求時狀態是 status:200 OK ,我是哪部分漏掉了嗎?我是用Laravel 8。

Victor iT邦新手 3 級 ‧ 2021-10-30 11:21:01 檢舉

您好 確認一下你的回傳是否有設定 201

AnimalController 檔案使用 Symfony Response 類別

use Symfony\Component\HttpFoundation\Response;

確認一下新增動物時是否有設定狀態碼,response 可以傳入兩個參數第一個參數是 body 內容,第二個參數設定狀態碼,這裡使用套件定義好的 Response::HTTP_CREATED 回傳 201 HTTP狀態碼。

return response($animal, Response::HTTP_CREATED);

參考:
這一天的文章 Day6
https://ithelp.ithome.com.tw/articles/10215878

謝謝您的回復,問題就出在引用到不同的Response類別,謝謝你。

我要留言

立即登入留言