Laravel如何使用Passport OAuth 进行用户登录认证

Laravel Passport 可以在几分钟之内为你的应用程序提供完整的 OAuth2 服务端实现。Passport 是基于由 Andy Millington 和 Simon Hamp 维护的 League OAuth2 server 建立的。

安装

在开始使用之前,使用 Composer 包管理器安装 Passport:

composer require laravel/passport

Passport 的 服务提供器 注册了自己的数据库迁移脚本目录, 所以你应该在安装软件包完成后迁移你自己的数据库。 Passport 的迁移脚本将为你的应用创建用于存储 OAuth2 客户端和访问令牌的数据表:

php artisan migrate

接下来,你需要执行 Artisan 命令 passport:install。这个命令将会创建一个用于生成安全访问令牌的加密秘钥。另外,这个命令也将创建用于生成访问令牌的 “个人访问” 客户端和 “密码授权” 客户端 :

php artisan passport:install

注意这里有一个坑

在进行数据库迁移的时候有时候会提示如下错误信息

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

这是数据库不支持长字节,默认情况下,laravel 使用 utf8mb4 编码。如果你是在版本低于 5.7.7 的 MySQL 或者版本低于 10.2.2 的 MariaDB 上创建索引,那你就需要手动配置数据库迁移的默认字符串长度。也就是说,你可以通过在 App\Providers\AppServiceProvider 类的 boot 方法中调用 Schema::defaultStringLength 方法来配置默认字符串长度:

use Illuminate\Support\Facades\Schema;

/**
 * 引导任何应用程序「全局配置」
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

执行完passport:install后会生成两个客户端秘钥

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

配置

在执行 passport:install 命令后, 添加 laravel\Passport\HasApiTokens trait 到你的 App\Models\User 模型中。 这个 trait 会提供一些帮助方法用于检查已认证用户的令牌和权限范围。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}

然后,在你应用的配置文件 config/auth.php 中, 将 api 的授权看守器 guards 的 driver 参数的值设置为 passport。此调整会让你的应用程序使用 Passport 的 TokenGuard 鉴权 API 接口请求:

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

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

默认情况下,Passport 会发行生命周期一年的长期 token 。如果要配置更长或更短生命周期的 token,可以使用 tokensExpireIn 、refreshTokensExpireIn 和 personalAccessTokensExpireIn 方法。这些方法需要在应用的 App\Providers\AuthServiceProvider 的 boot 方法中调用:

/**
 * 注册身份验证/授权服务
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();


    Passport::tokensExpireIn(now()->addDays(15));
    Passport::refreshTokensExpireIn(now()->addDays(30));
    Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}

发放access_token

场景一: 我的用户,在别的网站想用我的账号直接登录,参考微信登录。那么第三方网站就要对接过来,用户选择第三方登录,跳转到我的页面,询问用户是否允许,用户允许以后我会带一个code回去,第三方网站用这个code请求access_token

请求令牌

use Illuminate\Http\Request;
use Illuminate\Support\Str;

Route::get('/redirect', function (Request $request) {
    $request->session()->put('state', $state = Str::random(40));

    $query = http_build_query([
        'client_id' => 'client-id',
        'redirect_uri' => 'http://third-party-app.com/callback',
        'response_type' => 'code',
        'scope' => '',
        'state' => $state,
    ]);

    return redirect('http://passport-app.test/oauth/authorize?'.$query);
});

用户允许以后拿到code换token

如果用户授权了访问,他们会被重定向到业务服务端。(首先,业务端服务需要检查 state 参数是否和重定向之前存储的值一致,这一步骤可以根据自身需求而定)。 如果 state 参数的值正确,业务端服务器需要对你的应用发起获取 access token 的 POST 请求。 请求需要携带有授权码,授权码就是之前用户授权后由你的应用服务器生成的码:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

Route::get('/callback', function (Request $request) {
    $state = $request->session()->pull('state');

    throw_unless(
        strlen($state) > 0 && $state === $request->state,
        InvalidArgumentException::class
    );

    $response = Http::asForm()->post('http://passport-app.test/oauth/token', [
        'grant_type' => 'authorization_code',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'redirect_uri' => 'http://third-party-app.com/callback',
        'code' => $request->code,
    ]);

    return $response->json();
});

token如果过期了,可以刷新token

use Illuminate\Support\Facades\Http;

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

return $response->json();

场景二:这个主要是用于自己本身的项目,用户通过app等输入账号和密码,我用账号密码校验正确了就发送access_token

use Illuminate\Support\Facades\Http;

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

return $response->json();

这种跟第一种差不多,就是省去了code 直接发放,主要用于JavaScript 或移动应用中客户端登录认证信息不能保存时

在你使用密码授权方式发布令牌前,你需要先创建密码授权方式的客户端。你可以通过 Artisan 命令 passport:client , 并加上 --password 参数来创建这样的客户端。

如果你已经运行过 passport:install 命令,则不需要再运行下面的命令,因为他已经帮你默认创建两个了:

php artisan passport:client --password

使用

我们希望当用户注册成功之后返回token给app

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Http;

class RegisterController extends Controller
{
    private $http;
    public function __construct(Http $http)
    {
        $this->http = $http;
    }
    public function register(Request $request)
    {
        $user = User::create([
            'name'      => $request->name,
            'email'     => $request->email,
            'password'  => bcrypt($request->password)
        ]);
        $response = $this->http->post('http://passport-app.test/oauth/token', [
            'form_params' => [
                'grant_type' => 'password',
                'client_id' => 'client-id',
                'client_secret' => 'client-secret',
                'username' => $user->email,
                'password' => $request->password,
                'scope' => '*',
            ],
        ]);
        $token = json_decode((string) $response->getBody(), true);

        return response()->json([
            'token'=> $token
        ],200);
    }
}

以上这篇laravel如何使用Passport OAuth 进行用户登录认证就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持芦苇派。

原创文章,作者:ECHO陈文,如若转载,请注明出处:https://www.luweipai.cn/php/1670141287/

  • 0