Laravel 的 API 认证系统 Passport

介绍

在 Laravel 中,实现基于传统表单的登陆和授权已经非常简单,但是如何满足 API 场景下的授权需求呢?在 API 场景里通常通过令牌来实现用户授权,而非维护请求之间的 Session 状态。现在 Laravel 项目中可以使用 Passport 轻而易举地实现 API 授权过程,通过 Passport 可以在几分钟之内为你的应用程序添加完整的 OAuth2 服务端实现。 Passport 基于 League OAuth2 server 实现,该项目的维护人是 Alex Bilbie

{note} 本文档假定你已熟悉 OAuth2 。如果你并不了解 OAuth2 ,阅读之前请先熟悉下 OAuth2 的常用术语和基本特征。

安装

使用 Composer 依赖包管理器安装 Passport :

composer require laravel/passport

接下来,将 Passport 的服务提供者注册到配置文件 config/app.phpproviders 数组中:

Laravel\Passport\PassportServiceProvider::class,

Passport 使用服务提供者注册内部的数据库迁移脚本目录,所以上一步完成后,你需要更新你的数据库结构。Passport 的迁移脚本会自动创建应用程序需要的客户端数据表和令牌数据表:

php artisan migrate

{note} 如果你不打算使用 Passport 的默认迁移,你应该在AppServiceProviderregister方法中调用Passport :: ignoreMigrations方法。 你可以导出这个默认迁移用php artisan vendor:publish --tag=passport-migrations命令。

接下来,你需要运行 passport:install 命令来创建生成安全访问令牌时用到的加密密钥,同时,这条命令也会创建「私人访问」客户端和「密码授权」客户端:

php artisan passport:install

上面命令执行后,请将 Laravel\Passport\HasApiTokens Trait 添加到 App\User 模型中,这个 Trait 会给你的模型提供一些辅助函数,用于检查已认证用户的令牌和使用作用域:

<?php

namespace App;

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

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}

接下来,需要在 AuthServiceProviderboot 方法中调用 Passport::routes 函数。这个函数会注册一些在访问令牌、客户端、私人访问令牌的发放和吊销过程中会用到的必要路由:

<?php

namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();
    }
}

最后,需要将配置文件 config/auth.phpapi 部分的授权保护项( driver )改为 passport 。此调整会让你的应用程序在接收到 API 的授权请求时使用 Passport 的 TokenGuard 来处理:

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

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

前端快速上手

{note} 如果想要使用 Passport 的 Vue 组件,那么你必须使用 Vue Javascript 框架,另外这些组件还用到了 Bootstrap CSS 框架。当然你也可以不使用上面的任何工具,但在实现你自己的前端部分时,Passport 的 Vue 组件仍旧有很高的参考价值。

Passport 配备了一些可以让你的用户自行创建客户端和私人访问令牌的 JSON API。所以,你可以自己花费时间来编写一些前端代码来使用这些 API。当然在 Passport 中也已经预制了一些 Vue 组件,你可以直接使用这些示例代码,也可以基于这些代码实现自己的前端部分。

使用 Artisan 命令 vendor:publish 来发布 Passport 的 Vue 组件:

php artisan vendor:publish --tag=passport-components

已发布的组件将被放置在 resources/assets/js/components 目录中,可以在 resources/assets/js/app.js 文件中注册这些已发布的组件:

Vue.component(
    'passport-clients',
    require('./components/passport/Clients.vue')
);

Vue.component(
    'passport-authorized-clients',
    require('./components/passport/AuthorizedClients.vue')
);

Vue.component(
    'passport-personal-access-tokens',
    require('./components/passport/PersonalAccessTokens.vue')
);

这些组件注册后,你可以直接将这些组件直接放入应用程序的模板中,用于创建客户端和私人访问令牌:

<passport-clients></passport-clients>
<passport-authorized-clients></passport-authorized-clients>
<passport-personal-access-tokens></passport-personal-access-tokens>

配置

令牌的有效期

B默认情况下,Passport 发放的访问令牌是永久有效的,不需要刷新。但是如果你想给访问令牌配置一个短一些的有效期,那你就需要用到 tokensExpireInrefreshTokensExpireIn 方法了,上述两个方法同样需要在 AuthServiceProviderboot 方法中调用:

use Carbon\Carbon;

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    Passport::routes();

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

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

发放访问令牌

熟悉 OAuth2 的开发者一定知道, OAuth2 中必不可少的部分就是授权码。在获取授权码时,接入应用会重定向一个用户到你的服务端,用户可以选择允许或拒绝向这个客户端发放访问令牌。

管理客户端

首先,接入应用如果想要与你应用的 API 进行交互,必须先在你的应用程序中注册一个「客户端」。一般来说,这个注册过程需要开发者提供两部分信息:接入应用名称和用户授权后的跳转链接。

命令 passport:client

创建客户端最简单的方式是使用 Artisan 命令 passport:client ,你可以使用此命令创建自己的客户端,用于测试 OAuth2 的功能。在你执行 client 命令时,Passport 会提示输入更多关于你的客户端的信息,最终会提供给你生成的客户端的 ID 和 密钥:

php artisan passport:client

JSON API

考虑到你的用户们并没有办法使用 client 命令,Passport 同时提供了用户创建客户端的 JSON API 。这样你就不用再花时间编码来实现客户端创建、更新和删除的相关控制器逻辑了。

然而,你仍旧需要基于 Passport 的 JSON API 开发一套前端界面,方便你的用户管理他们授权的客户端。下面我们会列出所有用于管理客户端的 API,方便起见,我们使用 Vue 展示对 API 的 HTTP 请求。

{tip} 如果你不想自己重写整个客户端管理的前端界面,可以根据 前端快速上手 在几分钟内组建一套功能完备的前端界面。

GET /oauth/clients

此接口会返回当前认证用户的所有客户端。主要用途是列出当前用户所有客户端,方便用户修改或删除:

this.$http.get('/oauth/clients')
    .then(response => {
        console.log(response.data);
    });

POST /oauth/clients

此接口用户创建新&#x