总结原创
| 模式 | 优点 | 不足 | 使用场景 |
| :--------: | :---------------------: | :-----------: |
| 密码授权 | token有效期可以手动指定 | 无法切换guard | 只使用一个用户数据表进行认证,使用不同scope进行用户分组 |
| 个人访问端 | 也可以使用账号密码认证 | token不会过期 | 可以使用多个用户数据表进行认证 |
composer require laravel/passport # 安装拓展
php artisan passport:keys # 第一次部署时 生成新的密钥
php artisan vendor:publish --tag=passport-migrations # 导出passport默认迁移文件,并做相应的修改
php artisan migrate # 数据库迁移
php artisan passport:install --uuids # 使用uuid
# 修改文件
# 模型
在执行 passport:install
命令后, 添加 Laravel\Passport\HasApiTokens trait
到你的 App\Models\User
模型中。 这个 trait
会提供一些帮助方法用于检查已认证用户的令牌和权限范围。如果您的模型已经在使用 Laravel\Sanctum\HasApiTokens trait
,您可以删除该 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;
}
# 服务提供者
接着你需要在 App\Providers\AuthServiceProvider
类的 boot
方法中调用 Passport::routes
方法。这个方法将注册一些必须的路由,用于发布或撤销访问令牌,操作客户端以及个人的访问令牌:
点击查看
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport;
class AuthServiceProvider extends ServiceProvider
{
/**
* 应用的策略映射。
*
* @var array
*/
protected $policies = [
'App\Models\Model' => 'App\Policies\ModelPolicy',
];
/**
* 注册鉴权/授权服务。
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
if (! $this->app->routesAreCached()) {
Passport::routes();
Passport::tokensExpireIn(now()->addDays(15)); // token有效期 addMinutes addHours
Passport::refreshTokensExpireIn(now()->addDays(30)); // 刷新token 的有效期
Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}
}
}
# auth config
最后,在你应用的配置文件 config/auth.php
中, 将 api
的授权看守器 guards
的 driver
参数的值设置为 passport
。此调整会让你的应用程序使用 Passport
的 TokenGuard
鉴权 API
接口请求:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
# 自定义用户名字段
在对应模型中修改,如 User
模型。
/**
* 查找给定用户名的用户实例。
*
* @param string $username
* @return \App\Models\User
*/
public function findForPassport($username)
{
switch ($username) {
case filter_var($username, FILTER_VALIDATE_EMAIL): //判断账户是否是邮箱
return $this->where('email', $username)->first();
break;
case preg_match_all('/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[0-9]|18[0-9])\d{8}$/', $username) == 1: //验证是否是手机号号码
return $this->where('phone', $username)->first();
break;
case preg_match_all('/^([1-6][1-9]|50)\d{4}(18|19|20)\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/', $username) == 1: //验证是否是身份证号码
return $this->where('card_id', $username)->first();
break;
default:
return $this->where('user_name', $username)->first();
}
}
# 自定义密码验证
在对应模型中修改,如 User
模型。
/**
* 验证用户的密码以获得 Passport 密码授权。
*
* @param string $password
* @return bool
*/
public function validateForPassportPasswordGrant($password)
{
return Hash::check($password, $this->password);
}
# 未授权 处理
文件app/Exceptions/Handler.php
添加以下内容对 passport
授权失效坐判断。
点击查看
protected function unauthenticated($request, AuthenticationException $exception)
{
return response()->json([
'code'=> 401,
'message'=> '未授权!'
],401);
}
# 自定义 passport 路由
文件位置 vendor/laravel/passport/src/RouteRegistrar.php
注销对应的方法即可。
public function all()
{
$this->forAuthorization();
$this->forAccessTokens();
$this->forTransientTokens();
// $this->forClients();
$this->forPersonalAccessTokens();
}
# 单点登录
使用事件和监听,在 Laravel
应用中的 EventServiceProvider
注册passport
事件
protected $listen = [
……
// 添加 passport 事件
'Laravel\Passport\Events\AccessTokenCreated' => [
'App\Listeners\RevokeOldTokens',
],
'Laravel\Passport\Events\RefreshTokenCreated' => [
'App\Listeners\PruneOldTokens',
],
];
在 App\Listeners\RevokeOldTokens
定义:
public function handle(AccessTokenCreated $event)
{
DB::table('oauth_access_tokens')
->where('user_id',$event->userId)
->where('client_id',$event->clientId)
->where('id','<>',$event->tokenId)
->delete();
}
注意 DB
和 AccessTokenCreated
的引入。
# 解决跳转到 login
php artisan make:middleware Api/AcceptHeaderMiddleware
设置内容:
public function handle(Request $request, Closure $next)
{
$request->headers->set('Accept', 'application/json');
return $next($request);
}
其实就是请求头里增加 Accept:application/json
最后将该 中间件 添加到 app/Http/Kernel.php api
路由中间件组中。
protected $middlewareGroups = [
'api' => [
AcceptHeaderMiddleware::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
# 登录后,获取当前用户token
修改 过期时间
$token = auth()->user()->token(); //可以获取到当前用户的token
$token->expires_at = now()->addMinute(3); // ->addDays(15)
$token->save();
# bearerToken
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Lcobucci\JWT\Configuration;
class CheckApiTokenExpireInMiddleware
{
public function handle(Request $request, Closure $next)
{
// 获取请求头中的 token
$bearerToken=$request->bearerToken();
// passport ^10.4 从 bearerToken 获取token解析后的相关字段,如 jti
// use Lcobucci\JWT\Configuration;
$tokenId = Configuration::forUnsecuredSigner()->parser()->parse($bearerToken)->claims()->get('jti');
$exp = Configuration::forUnsecuredSigner()->parser()->parse($bearerToken)->claims()->get('exp');
$userId = Configuration::forUnsecuredSigner()->parser()->parse($bearerToken)->claims()->get('sub');
$clientId = Configuration::forUnsecuredSigner()->parser()->parse($bearerToken)->claims()->get('aud');
dd($tokenId,$exp,now(),$userId,$clientId);
$psr = $this->server->validateAuthenticatedRequest($request->bearerToken());
// dd($request->bearerToken());
return $next($request);
}
}
笔记
laravel/passport": "^8.0
使用:
use Lcobucci\JWT\Parser;
$bearerToken = request()->bearerToken();
$tokenId = (new Parser())->parse($bearerToken)->getClaim('jti');