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

利用Laravel 搭建oauth2 API接口

要求

laravel 5.4以上php

安裝

$ composer require laravel/passportlaravel

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

LaravelPassportPassportServiceProvider::class,數據庫

遷移數據庫 執行完後會生成oauth須要的表json

$ php artisan migrateapi

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

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

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

解決方法就是composer

  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/...

相關文章
相關標籤/搜索