Laravel5.6 + Passport 實現 API 介面認證

huangdj 發表於2019-09-11

很多企業做專案使用前後端分離,後端提供介面地址,前端使用介面地址拿資料,並渲染頁面。那麼,前端使用者登入如何使用介面進行認證?網上各種教程寫的不堪入目,完全看不懂,所以我根據自己的理解,寫下此篇文章,希望能幫助到大家。

後端(Laravel5.6框架)

1、使用composer安裝Passport,開啟終端,執行命令:

composer require laravel/passport   #安裝完成後,在composer.json檔案中會看到檔案版本資訊

2、接下來,將Passport的服務提供者註冊到配置檔案config/app.phpproviders陣列中

Laravel\Passport\PassportServiceProvider::class,

3、執行資料庫遷移

php artisan migrate  #資料庫中會生成介面認證所需的5張表

4、建立密碼授權客戶端

php artisan passport:client --password
#建立了client_id和client_secret,前端登入驗證的時候必須把這兩個玩意兒帶著

5、獲取keys

php artisan passport:keys

6、配置路由
開啟服務提供者AuthServiceProvider, 在boot方法中加入如下程式碼:

use Laravel\Passport\Passport;
public function boot() { 
    $this->registerPolicies();  
    Passport::routes(); //介面認證的路由
}

然後將配置檔案config/auth.php中授權看守器guardsapidriver選項改為passport
我這裡的customer表是前端使用者表,但是laravel預設的是user表,所以這裡需要做如下配置:

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'customers',
    ],
],
'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\User::class,
    ],
    'customers' => [
        'driver' => 'eloquent',
        'model' => App\Models\Shop\Customer::class,
    ],
],

7、註冊中介軟體,在app/Http/Kernel.php檔案中的$routeMiddleware陣列中新增如下中介軟體

protected $middleware = [
    \App\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \App\Http\Middleware\TrustProxies::class,
    \Barryvdh\Cors\HandleCors::class,
];

**********************************************************************

protected $routeMiddleware = [
'client.credentials'=>\Laravel\Passport\Http\Middleware\CheckClientCredentials::class,
];

然後在需要認證介面路由檔案routes/api.php前面加上這個中介軟體。

Route::prefix('cart')->middleware('client.credentials')->group(function(){
    ...
});

8、前端使用者表customer模型裡面做如下配置:

use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;

class Customer extends Authenticatable
{
    use HasApiTokens;
     ....   
}

至此,後端的所有配置已完成。

接下來,開啟介面測試工具(postman),輸入介面地址:wechat.test/oauth/token,請求型別 POST,填上如下引數,點選 send 你會看到後臺返回了前端所需的access_token

前端(vue.js)

首先去載入使用者登入元件,即使用者登入頁面。

  1. 配置路由,在index.js檔案中寫入如下程式碼
import Login from '@/components/customer/Login'
export default new Router({
  routes: [
        ....
    {
      path: '/customer/login',
      name: 'Login',
      component: Login
    },
  ]
})

2、載入元件,在customer資料夾的Login.vue檔案中寫入如下程式碼:

<template>
  <div>
    <input type="email" v-model="customer.email" placeholder="請輸入郵箱">
    <input type="password" v-model="customer.password" placeholder="請輸入密碼">
    <button @click="submit">登 錄</button>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        customer: {
          email: '',
          password: ''
        }
      }
    },
    methods: {
      submit() {
        //將資料配置好
        const data = {
          grant_type: 'password', //oauth的模式
          client_id: 1,   //上面所說的client_id
          client_secret: 'CO331cA1mqiKgGvvgiDzPxh4CUu19vSEiqxM7LHD',//同上
          username: this.customer.email,
          password: this.customer.password,
        }
        this.axios.post('/oauth/token', data)
          .then(res => {
            if (res.status == 200) { //如果成功了,就把access_token存入localStorage
              localStorage.token_type = res.data.token_type
              localStorage.access_token = res.data.access_token
              this.$router.push({name:'Index'})
            }
          })
      }
    }
  }
</script>

客戶端檢視localStorage,如圖:

3、在http.js檔案中設定攔截器,用於判斷使用者是否登入,若沒有登入跳轉到登入頁面。程式碼如下:

//#建立http.js檔案
import axios from 'axios'
import router from '@/router'

// axios 配置
axios.defaults.timeout = 5000;
axios.defaults.baseURL = 'http://wechat.test/';

// http request 攔截器
axios.interceptors.request.use(
  config => { //將所有的axios的header里加上token_type和access_token
    config.headers.Authorization = `${localStorage.token_type} ${localStorage.access_token}`;
    return config;
  },
  err => {
    return Promise.reject(err);
  });

// http response 攔截器
axios.interceptors.response.use(
  response => {
    return response;
  },
  error => {
    // 401 清除token資訊並跳轉到登入頁面
    if (error.response.status == 401) {
      alert('您還沒有登入,請先登入')
      router.replace({    //如果失敗,跳轉到登入頁面
        name: 'Login'
      })
    }
    return Promise.reject(error.response.data)
  });

export default axios;

重新訪問專案,在商品詳情頁面點選加入購物車,你會發覺奇蹟已經出現,當你沒有登入時,提示跳轉到登入頁面。輸入賬號密碼,登入成功,此時就能拿到使用者id。接下來,繼續測試。

4、去Cart控制器中,找到購物車首頁方法,獲取使用者的id,獲取方式如下:

$customer_id = auth('api')->user()->id;
return $customer_id;

5、在postman中輸入購物車首頁介面地址,並傳入所需引數,引數參考地址:http://laravelacademy.org/post/8909.html,如圖:

拿到使用者id後,把後端之前定義的customer_id全部改為通過介面方法獲取。至此,Passport介面認證的全部操作已完成。

Tips:如果你在專案中跑passport命令執行報錯的話,可參考這篇文章來解決問題:https://laravel-china.org/topics/16245

總結:介面認證邏輯思想

1、安裝passport後,生成client_idclient_secret
2、使用usernamepasswordclient_idclient_secretgrant_type引數,呼叫/oauth/token介面,拿到access_token
3、需要認證的介面,加上中介軟體。這時候直接訪問介面地址,會提示沒有認證的。帶上access_token後,才能拿到介面的資料。