利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解決辦法


利用Laravel 搭建oauth2 API接口

要求

laravel 5.4以上

安裝

$ composer require laravel/passport

在配置文件 config/app.php 的providers 數組中注冊 Passport 服務提供者:

LaravelPassportPassportServiceProvider::class,

遷移數據庫 執行完后會生成oauth需要的表

$ php artisan migrate

這一步注意,執行的時候可能會報錯

Syntax error or access violation: 1071 Specified key was too long; max key length is 767 byte

這是由於 Laravel5.4默認使用utf8mb4 編碼
utf8 最大長度字符是3字節 utf8mb4是4字節

解決方法就是

  1. 數據庫改用utf8mb4

  2. AppServiceProvider.php里面加上Schema::defaultStringLength(191);

<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Schema; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { // Schema::defaultStringLength(191); } /** * Register any application services. * * @return void */ public function register() { // } } 

另外Mysql 5.5.3之后才支持utf8mb4也需要注意下

接下來執行

$ php artisan passport:install

會生成兩個客戶端密鑰

Client ID: 1
Client Secret: AwDMcCs65rXkzF80wPaINx5fkoXEfa8lcuuPEvQK
Password grant client created successfully. Client ID: 2 Client Secret: KLlLijWk3hX2Ntfzo2iFPgwT4GyITpBjEuDozp5H

配置

這里可以配置的只有access token的生命周期默認是永久的
在AuthServiceProvider中配置

use Carbon\Carbon; use Laravel\Passport\Passport; /** * 注冊所有認證/授權服務. * * @return void */ public function boot() { $this->registerPolicies(); Passport::routes(); Passport::tokensExpireIn(Carbon::now()->addDays(15)); Passport::refreshTokensExpireIn(Carbon::now()->addDays(30)); }

修改auth.php
'guards'['driver'] => 'passport'

發放access_token

頒發

應用場景 我的用戶,在別的網站想用我的賬號直接登錄,參考微信登錄。那么第三方網站就要對接過來,用戶選擇第三方登錄,跳轉到我的頁面,詢問用戶是否允許,用戶允許以后我會帶一個code回去,第三方網站用這個code請求access_token

流程是

請求令牌

    
    'client_id' => 'client-id', 'redirect_uri' => 'http://example.com/callback', 'response_type' => 'code', 'scope' => '',

用戶允許以后拿到code換token

 $response = $http->post('http://your-app.com/oauth/token', [ 'form_params' => [ 'grant_type' => 'authorization_code', 'client_id' => 'client-id', 'client_secret' => 'client-secret', 'redirect_uri' => 'http://example.com/callback', 'code' => $request->code, ], ]);

token如果過期了,可以刷新

$response = $http->post('http://your-app.com/oauth/token', [ 'form_params' => [ 'grant_type' => 'refresh_token', 'refresh_token' => 'the-refresh-token', 'client_id' => 'client-id', 'client_secret' => 'client-secret', 'scope' => '', ], ]);

賬號密碼

這個主要是用於APP(我自己的),用戶通過app輸入賬號和密碼,我用賬號密碼校驗正確了就發送access_token

$response = $http->post('http://your-app.com/oauth/token', [ 'form_params' => [ 'grant_type' => 'password', 'client_id' => 'client-id', 'client_secret' => 'client-secret', 'username' => 'taylor@laravel.com', 'password' => 'my-password', 'scope' => '', ], ]);

隱式

這種跟第一種差不多,就是省去了code 直接發放,主要用於

JavaScript 或移動應用中客戶端登錄認證信息不能保存時

客戶端證書

這種主要用於機器之間的通信
直接用appid 和 appsecret 換令牌

$response = $guzzle->post('http://your-app.com/oauth/token', [ 'form_params' => [ 'grant_type' => 'client_credentials', 'client_id' => 'client-id', 'client_secret' => 'client-secret', 'scope' => 'your-scope', ], ]);

私人訪問令牌

這個用於在程序里面調用API的時候
比如

$user = App\User::find(1); // 創建一個不帶域的令牌... $token = $user->createToken('Token Name')->accessToken; // 創建一個帶域的令牌... $token = $user->createToken('My Token', ['place-orders'])->accessToken;

在調用api之前需要創建client
創建命令是
$ php artisan passport:client

密碼和私人的不同其他都一樣

$ php artisan passport:client --password
$ php artisan passport:client --personal

創建好后獲得client-id和client-secret

創建路由

5.4以后目錄結構發生變化,路由統一寫在routes文件夾下。
API的路由都寫在api.php

確定好路由就可以請求接口了

GET 方式
    /api/user
    'headers' => [ 'Accept' => 'application/json', 'Authorization' => 'Bearer '.$accessToken, ],

寫到這里遇到一個問題

就是無論怎樣請求 獲取到的token 用來訪問接口的時候 總是返回
Unauthenticated

GOOGLE了下發現好多人也遇到這個問題,據說是token過期時間的問題

在AuthServiceProvider boot里面加上

Passport::tokensExpireIn(Carbon::now()->addDays(15)); Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));

這樣應該會解決,然而並沒有,這里等以后一時間再研究下(已解決 見下文)

這個問題有了一定進展

目前通過用戶授權頒發令牌的方式通過了

前提是用戶必須登錄,之前返回Unauthenticated 應該是因為用戶未登錄

在應用站跳轉到授權站的時候,此時用戶需登錄狀態,授權以后拿到code再來換access_token 這個方式OK的,可以正常獲取登錄用戶的信息

賬號密碼獲取令牌的方式也一樣可以通過

站點之前通過 id 和 secret的方式換token,然后拿token請求接口這種方式目前還不行

坑爹啊,官方文檔沒寫全

通過 client_credentials 方式獲取token,請求接口的時候,路由不能用auth或者scope等中間件去驗證,因為他們會首先驗證有沒有登錄。

我們需要在app\Http\Kernel.php 的 $routeMiddleware 里面定義一個客戶端API的中間件

'client_credentials' => \Laravel\Passport\Http\Middleware\CheckClientCredentials::class,

然后在路由里面
Route::middleware('client_credentials')

或者

Route::middleware('client_credentials:作用域名稱')

這樣就可以實現不登錄直接調用api了

參考文檔

https://laravel.com/docs/5.4/...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM