Laravel API 认证(Passport OAuth)

老牛浏览 441评论 0发表于

1. 介绍

Laravel 中,实现基于传统表单的登录和授权已经非常简单,但是如何满足 API 场景下的授权需求呢?在 API 场景里通常通过令牌来实现用户授权,而非维护请求之间的 Session 状态。我们可以使用 Passport 轻而易举的实现 API 授权认证,Passport 可以在几分钟内为应用程序提供完整的 OAuth2 服务端实现。Passport 是基于由 Alex Bilbie 维护的 League OAuth2 Server 建立的。

2. 安装

2.1 Composer 安装

在开始之前,请通过 Composer 包管理器安装 Passport:

bash
composer require laravel/passport

Laravel 5.5 需要指定适配版本:

bash
composer require laravel/passport=~4.0

如果 paragonie/random_compat 出现依赖版本冲突,可以先安装低版本:

bash
composer require paragonie/random_compat:2.*

然后再安装 passport 即可。

2.2 生成数据表

Passport 扩展包里已经自动注册了迁移文件加载,执行 migrate 会自动运行扩展包里的迁移文件,由此来创建存储客户端和令牌的数据表:

bash
php artisan migrate

如果不打算使用 Passport 的默认迁移,可以在 AppServiceProviderregister 方法中调用 Passport::ignoreMigrations 方法。然后通过 php artisan vendor:publish --tag=passport-migrations 导出默认迁移。

默认会生成 5 张数据表:

  • oauth_access_tokens

  • oauth_auth_codes

  • oauth_clients

  • oauth_personal_access_clients

  • oauth_refresh_tokens

2.3 创建加密密钥

接下来,运行 passport:keys 命令来创建安全访问令牌时所需的加密密钥:

bash
php artisan passport:keys

执行成功后,会在 storage 目录中看到两个以 oauth 开头的密钥对。

2.4 创建客户端

bash
php artisan passport:client --password --name='bbs-ios'

passport:client 命令可以创建一个客户端,由于我们使用的是密码模式,所以需要增加 --password 参数。同时还可以增加 --name 参数为客户端起个名字,这里我们起名为 bbs-ios

命令行中已经输出了创建了 client_idclient_secret

3. 调试

3.1 注册路由

安装好了 Passport 我们来调试一下,Passport::routes() 为我们提供了基础路由,我们先注册一下路由。

app/Providers/AuthServiceProvider.php

php
.
.
.
use Carbon\Carbon;
use Laravel\Passport\Passport;
.
.
.
public function boot()
{
    $this->registerPolicies();

    // Passport 的路由
    Passport::routes();
    // access_token 过期时间
    Passport::tokensExpireIn(Carbon::now()->addDays(15));
    // refresh_token 过期时间
    Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));
}

我们注册了路由,同时通过 Passport 的 tokensExpireInrefreshTokensExpireIn 定义了访问令牌的过期时间,否则令牌是永久有效的。这里我们定义 access_token 15 天内有效,refresh_token 30 天内有效。

3.2 获取访问令牌

密码模式我们通过 domain.com/oauth/token 这个路由来获取访问令牌。提交的参数如下:

  • grant_type - 密码模式固定为 password

  • client_id - 通过 passport:client 创建的客户端 id

  • client_secret - 通过 passport:client 创建的客户端 secret

  • username - 登录的用户名;

  • password - 用户密码;

  • scope - 作用域,可填写 * 或者为空。

提交正确的 client 信息以及任意已存在用户的用户名和密码,即可获取到访问令牌:

  • token_type - 令牌类型;

  • expires_in - 多久之后过期,单位:秒;

  • access_token - 访问令牌;

  • refresh_token - 刷新令牌。

3.3 刷新访问令牌

刷新访问令牌和获取访问令牌的接口地址一样,只是参数不同:

  • grant_type - 刷新令牌固定为 refresh_token

  • client_id - 通过 passport:client 创建的客户端 id

  • client_secret - 通过 passport:client 创建的客户端 secret

  • refresh_secret - 刷新令牌;

  • scope - 作用域,可填写 * 或者为空。

刷新令牌不用提交用户的用户名和密码,而是直接使用 refresh_token 换取新的访问令牌。

为什么要刷新 Access Token 呢?

  • 一是因为 Access Token 是由过期时间的,到了过期时间这个 Access Token 就会失效,需要刷新;

  • 二是因为一个 Access Token 会关联一定的用户权限,如果用户授权更改了,这个 Access Token 需要被刷新以关联新的权限。

为什么要专门用一个 Refresh Token 去更新 Access Token 呢?如果没有 Refresh Token,也可以更新,但每次都要用户手动输入用户名与密码,比较麻烦。有了 Refresh Token,就无需用户进行登录操作。

Refresh Token 也有过期时间,但是相对较长。Refresh Token 对存储的要求通常会非常严格,以确保它不会被泄露;Access Token 和 Refresh Token 都可以被授权服务器列入黑名单。

4. 获取用户登录信息

有了访问令牌,我们就能通过令牌获取个人用户信息了,不过在这之前我们需要修改一些配置。

Laravel\Passport\HasApiTokens 这个 Trait 添加到用户模型中,来给模型提供一些辅助函数,用于检查已认证用户的令牌和使用范围:

app/User.php

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;
}

修改 auth 配置,将 api guard 的 drivertoken 修改为 passport

config/auth.php

php
.
.
.
'guards' => [
.
.
.
    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
]
.
.
.
点赞
收藏
暂无评论,快来发表评论吧~
私信
老牛@ilaoniu
老牛,俗称哞哞。单纯的九零后理工小青年。喜欢折腾,爱玩,爱音乐,爱游戏,爱电影,爱旅游...
最后活跃于