Laravel Passport 原文档地址:learnku.com/docs/larave…
介绍
Laravel Passport 可以在几分钟之内为你的应用程序提供完整的 OAuth2 服务端实现。Passport 是基于由 Andy Millington 和 Simon Hamp 维护的 League OAuth2 server 建立的。 除非您需要所有的oauth服务,否则还是更推荐您使用轻量级的Sanctum进行认证处理
Sanctum登录:juejin.cn/post/721654…
1、Laravel Passport扩展
- 安装扩展
composer required laravel/passport
- 执行迁移
php artisan migrate - 创建客户端
php artisan passport:install(产出clint_id和client_secret要存好) - 在User模型中加入trait(你必须确保该trait是
Laravel\Passport\HasApiTokens)
<?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',
],
],
- 发布配置文件
php artisan vendor:publish --tag=passport-config
- 如果你需要设置Token的生命周期,需要在
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));
}
- 创建密码方式客户端
php artisan passport:client --password
- 配置用户名字段(兼容手机号邮箱)
/**
* Find the user instance for the given username.
*/
public function findForPassport(string $username): User
{
// 手机号或邮箱登录
filter_var($username, FILTER_VALIDATE_EMAIL) ? $credentials['email'] = $username : $credentials['mobile'] = $username;
return self::where($credentials)->first();
}
- 请求令牌
你的控制器要继承
Laravel\Passport\Http\Controllers\AccessTokenController类
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Response;
use Laravel\Passport\Http\Controllers\AccessTokenController;
use Psr\Http\Message\ServerRequestInterface;
class LoginController extends AccessTokenController
{
/**
* 登录.
*
* @note login
* @author Kevin
* @param ServerRequestInterface $request
* @return Response
*/
public function login(ServerRequestInterface $request)
{
$getBody = $request->getParsedBody();
// 配置作用域,不使用scope可传*或不传
$scope = request()->header('source', 'pc');
$scopes = [$scope];
$newBody = array_merge(
[
'client_id' => config('system.login.oauth_client.password.client_id'),
'client_secret' => config('system.login.oauth_client.password.client_secret'),
'scope' => $scopes,
],
$getBody
);
$newRequest = $request->withParsedBody($newBody);
return $this->issueToken($newRequest)->setStatusCode(200);
}
}
- 如果你需要使用作用域:
设置作用域
你可以在 App\Providers\AuthServiceProvider 的 boot 方法中使用 Passport::tokensCan 方法来定义 API 的作用域
/**
* 注册身份验证/授权服务。
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Passport::tokensCan([
'place-orders' => 'Place orders',
'check-status' => 'Check order status',
]);
}
应用作用域
检查作用域
Passport 包含两个中间件,可用于验证传入的请求是否包含访问指定作用域的令牌。 使用之前,需要将下面的中间件添加到 app/Http/Kernel.php 文件的 $routeMiddleware 属性中:
'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
检查所有作用域
路由可以使用 scopes 中间件来检查当前请求是否拥有指定的 所有 作用域:
Route::get('/orders', function () {
// 访问令牌具有 "check-status" 和 "place-orders" 作用域...
})->middleware(['auth:api', 'scopes:check-status,place-orders']);
检查任意作用域
路由可以使用 scope 中间件来检查当前请求是否拥有指定的 任意 作用域:
Route::get('/orders', function () {
// 访问令牌具有 "check-status" 或 "place-orders" 作用域...
})->middleware(['auth:api', 'scope:check-status,place-orders']);
- 路由保护
通过中间件,
Passport 包含一个 验证保护机制 验证请求中传入的访问令牌。 若配置
api的看守器使用passport驱动,你只要在需要有效访问令牌的路由上指定auth:api中间件即可
Route::get('/user', function () {
//
})->middleware('auth:api');
2、教程包kslimani/laravel-passport-grant(扩展登录方式)
- 安装扩展
composer require kslimani/laravel-passport-grant
- 发布配置文件
php artisan vendor:publish --provider="Sk\Passport\GrantTypesServiceProvider" --tag="config"
- 使用扩展(在
App/Passport下创建文件进行关联)
这样就会根据登录接口grant_type参数值匹配provider进行执行,可在provider中进行逻辑处理,登录成功与否取决于此文件返回值是null还是一个User模型,例如;
<?php
declare(strict_types=1);
namespace App\Passport;
use App\Models\User;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Support\Facades\Hash;
use Psr\Http\Message\ServerRequestInterface;
use Sk\Passport\UserProvider;
class PasswordUserProvider extends UserProvider
{
public function validate(ServerRequestInterface $request)
{
$this->validateRequest($request, [
'username' => 'required|string',
'password' => 'required|string',
]);
}
/**
* 操作.
*
* @note retrieve
* @author Kevin
*
* @param ServerRequestInterface $request
* @return null|mixed|User
* @throws AuthenticationException
*/
public function retrieve(ServerRequestInterface $request)
{
$inputs = $this->only($request, [
'username',
'password',
]);
try {
$user = app(User::class)->findForPassport($inputs['username']);
if (is_null($user) || !Hash::check($inputs['password'], $user->password)) {
throw new AuthenticationException('账号或密码输入有误');
}
return $user;
} catch (AuthenticationException $exception) {
// log
throw new AuthenticationException($exception->getMessage());
}
}
}