2.腾讯审核认证通过后,返回给 App_id,App_key
3.客户把 App_id,App_key 给到自己的网站后台
4.用户 a 在登录的时候选择 QQ 登录,这个时候,客户的网站会组织好请求参数,向腾讯发起授权登录请求
5.腾讯收到授权登录请求之后,它会进行核对,是否放行,然后经过一些列通过之后,返回 code 给到商户
6.商户收到 code,发起获取用户信息
7.腾讯通过 code 确认认证之后,返回给相应的权限信息
8.客户网站收到返回的信息,进行本地会员进行登录操作。
这个就是典型的流程操作。
这个时候,我们可以规划出表有几个了
服务器端:必须有商户表,也就是客户端表,
Laravel passport 的对应表是
OAuth_clients
认证客户端
商户发起请求之后,他会有个认证授权的认证码表,
OAuth_auth_codes
认证 code 表
后来商户再次发起获得用户相关权限信息,这个时候,服务端需要分配 token 值,那么这个时候,就需要一个 token 存储表
OAuth_access_tokens
通过认证 token 表,这个授权 token 表,他也会有过期时间,过期了,我们需要发起刷新 token,那么我们就需要一个刷新 token 表
OAuth_refresh_tokens
刷新 token 表
这里 4 个表就可以完成一套 auth2.0 的授权操作了。
那么 Laravel passport 它还有一个表
OAuth_personal_access_clients
个人授权客户端
这里只是记录了私人客户端的记录表,只是记录而已
这个我之前分享过,可我那个时候没去管实际用途场景
那么我们平台使用的场景到底如何呢?
假设我现在后台,我需要给小程序 A 一个接口分配一个密钥对,支付宝小程序一个密钥对,或者是我给第三方接入我们的数据密钥对,那么我们现在就可以用 Laravel passport 来做了
1.第一个后台创建客户端,比如给小程序用的,支付宝小程序,第三方小明 A
2.将这些信息分别发给他们对应的开发者,那样我们就能很好的区分出来,这些 token 属于谁的来源
3.其他他要完成什么操作,就还是那样操作。
4.因为这里是不需要点击授权的操作,因此可以使用密码授权或者是个人授权认证。
5.注意的是个人授权,需要把他的客户端 id 进行设置下 Passport::personalAccessClientId (2);
那样创建的会员 token 才能在指定的位置,个人授权是没用刷新 token 的,所以就只能看到 3 个表个数据
客户端,token 表,个人客户端关系表
密码授权令牌
表数据必须是:
默认的密钥放在 /storage/ 下
\vendor\Laravel\passport\src\Passport.php
里面设置加密密钥位置
public static function keyPath ($file)
$file = ltrim ($file, '/\\');
return static::$keyPath
? rtrim (static::$keyPath, '/\\') . DIRECTORY_SEPARATOR . $file
: storage_path ($file);
Passport 密钥的加载路径,这可以通过使用 Passport::loadKeysFrom 方法来实现
Passport::loadKeysFrom ('/secret-keys/OAuth');
令牌生命周期
// 有效期
Passport::tokensExpireIn (now ()->addDays (15));
// 过期刷新时间
Passport::refreshTokensExpireIn (now ()->addDays (30));
具体查看这个页面
Passport.php
<?PHP
namespace Laravel\Passport;
use Mockery;
use DateInterval;
use Carbon\Carbon;
use DateTimeInterface;
use Illuminate\Support\Facades\Route;
class Passport
* Indicates if the implicit grant type is enabled.
*指示是否启用隐式授予类型。
* @var bool|null
public static $implicitGrantEnabled = false;
* Indicates if Passport should revoke existing tokens when issuing a new one.
*指示 Passport 在颁发新令牌时是否应吊销现有令牌。
* @var bool
public static $revokeOtherTokens = false;
* Indicates if Passport should prune revoked tokens.
*指示 Passport 是否应删除吊销的令牌。
* @var bool
public static $pruneRevokedTokens = false;
* The personal access token client ID.
*个人访问令牌客户端 ID。
* @var int
public static $personalAccessClientId;
* The default scope.
*默认范围。
* @var string
public static $defaultScope;
* All of the scopes defined for the application.
*为应用程序定义的所有范围。
* @var array
public static $scopes = [
* The date when access tokens expire.
*访问令牌到期的日期。
* @var \DateTimeInterface|null
public static $tokensExpireAt;
* The date when refresh tokens expire.
*刷新令牌到期的日期。
* @var \DateTimeInterface|null
public static $refreshTokensExpireAt;
* The date when personal access tokens expire.
*个人访问令牌到期的日期。
* @var \DateTimeInterface|null
public static $personalAccessTokensExpireAt;
* The name for API token cookies.
*API 令牌 cookie 的名称。
* @var string
public static $cookie = 'Laravel_token';
* Indicates if Passport should ignore incoming CSRF tokens.
*指示 Passport 是否应忽略传入的 CSRF 令牌。
* @var bool
public static $ignoreCsrfToken = false;
* The storage location of the encryption keys.
*加密密钥的存储位置。
* @var string
public static $keyPath;
* The auth code model class name.
*身份验证代码模型类名称。
* @var string
public static $authCodeModel = 'Laravel\Passport\AuthCode';
* The client model class name.
* 客户端模型类
* @var string
public static $clientModel = 'Laravel\Passport\Client';
* The personal access client model class name.
*个人访问客户端模型类名称。
* @var string
public static $personalAccessClientModel = 'Laravel\Passport\PersonalAccessClient';
* The token model class name.
*令牌模型类名称。
* @var string
public static $tokenModel = 'Laravel\Passport\Token';
* Indicates if Passport migrations will be run.
*指示是否将运行 Passport 迁移。
* @var bool
public static $runsMigrations = true;
* Indicates if Passport should unserializes cookies.
*指示 Passport 是否应该反序列化 cookie。
* @var bool
public static $unserializesCookies = false;
* Enable the implicit grant type.
*启用隐式授权类型。
* @return static
public static function enableImplicitGrant ()
static::$implicitGrantEnabled = true;
return new static;
* Binds the Passport routes into the controller.
* @param callable|null $callback
* @param array $options
* @return void
public static function routes ($callback = null, array $options = [])
$callback = $callback ?: function ($router) {
$router->all ();
$defaultOptions = [
'prefix' =>'OAuth',
'namespace' =>'\Laravel\Passport\Http\Controllers',
$options = array_merge ($defaultOptions, $options);
Route::group ($options, function ($router) use ($callback) {
$callback (new RouteRegistrar ($router));
* Instruct Passport to revoke other tokens when a new one is issued.
* 指示 Passport 在发布新令牌时撤消其他令牌。
* @deprecated since 1.0. Listen to Passport events on token creation instead.
* @return static
public static function revokeOtherTokens ()
return new static;
* Instruct Passport to keep revoked tokens pruned.
*指示 Passport 保留已撤销的撤销令牌。
* @deprecated since 1.0. Listen to Passport events on token creation instead.
* @return static
public static function pruneRevokedTokens ()
return new static;
* Set the client ID that should be used to issue personal access tokens.
*设置应该用于颁发个人访问令牌的客户端 ID。
* @param int $clientId
* @return static
public static function personalAccessClientId ($clientId)
static::$personalAccessClientId = $clientId;
return new static;
* Set the default scope (s). Multiple scopes may be an array or specified delimited by spaces.
* @param array|string $scope
* @return void
public static function setDefaultScope ($scope)
static::$defaultScope = is_array ($scope) ? implode (' ', $scope) : $scope;
* Get all of the defined scope IDs.
*获取所有已定义的范围 ID。
* @return array
public static function scopeIds ()
return static::scopes ()->pluck ('id')->values ()->all ();
* Determine if the given scope has been defined.
**确定是否已定义给定范围。
* @param string $id
* @return bool
public static function hasScope ($id)
return $id === '*' || array_key_exists ($id, static::$scopes);
* Get all of the scopes defined for the application.
* @return \Illuminate\Support\Collection
public static function scopes ()
return collect (static::$scopes)->map (function ($description, $id) {
return new Scope ($id, $description);
})->values ();
* Get all of the scopes matching the given IDs.
*获取与给定 ID 匹配的所有范围。
* @param array $ids
* @return array
public static function scopesFor (array $ids)
return collect ($ids)->map (function ($id) {
if (isset (static::$scopes [$id])) {
return new Scope ($id, static::$scopes [$id]);
return;
})->filter ()->values ()->all ();
* Define the scopes for the application.
*定义访问程序的范围。
* @param array $scopes
* @return void
public static function tokensCan (array $scopes)
static::$scopes = $scopes;
* Get or set when access tokens expire.
*访问令牌到期时获取或设置。
* @param \DateTimeInterface|null $date
* @return \DateInterval|static
public static function tokensExpireIn (DateTimeInterface $date = null)
if (is_null ($date)) {
return static::$tokensExpireAt
? Carbon::now ()->diff (static::$tokensExpireAt)
: new DateInterval ('P1Y');
static::$tokensExpireAt = $date;
return new static;
* Get or set when refresh tokens expire.
*刷新令牌过期时获取或设置。
* @param \DateTimeInterface|null $date
* @return \DateInterval|static
public static function refreshTokensExpireIn (DateTimeInterface $date = null)
if (is_null ($date)) {
return static::$refreshTokensExpireAt
? Carbon::now ()->diff (static::$refreshTokensExpireAt)
: new DateInterval ('P1Y');
static::$refreshTokensExpireAt = $date;
return new static;
* Get or set when personal access tokens expire.
*个人访问令牌到期时获取或设置。
* @param \DateTimeInterface|null $date
* @return \DateInterval|static
public static function personalAccessTokensExpireIn (DateTimeInterface $date = null)
if (is_null ($date)) {
return static::$personalAccessTokensExpireAt
? Carbon::now ()->diff (static::$personalAccessTokensExpireAt)
: new DateInterval ('P1Y');
static::$personalAccessTokensExpireAt = $date;
return new static;
* Get or set the name for API token cookies.
*获取或设置 API 令牌 cookie 的名称。
* @param string|null $cookie
* @return string|static
public static function cookie ($cookie = null)
if (is_null ($cookie)) {
return static::$cookie;
static::$cookie = $cookie;
return new static;
* Indicate that Passport should ignore incoming CSRF tokens.
* @param bool $ignoreCsrfToken
* @return static
public static function ignoreCsrfToken ($ignoreCsrfToken = true)
static::$ignoreCsrfToken = $ignoreCsrfToken;
return new static;
* Set the current user for the application with the given scopes.
*使用给定范围设置应用程序的当前用户。
* @param \Illuminate\Contracts\Auth\Authenticatable|\Laravel\Passport\HasApiTokens $user
* @param array $scopes
* @param string $guard
* @return \Illuminate\Contracts\Auth\Authenticatable
public static function actingAs ($user, $scopes = [], $guard = 'API')
$token = Mockery::mock (Passport::tokenModel ())->shouldIgnoreMissing (false);
foreach ($scopes as $scope) {
$token->shouldReceive ('can')->with ($scope)->andReturn (true);
$user->withAccessToken ($token);
if (isset ($user->wasRecentlyCreated) && $user->wasRecentlyCreated) {
$user->wasRecentlyCreated = false;
App ('auth')->guard ($guard)->setUser ($user);
App ('auth')->shouldUse ($guard);
return $user;
* Set the storage location of the encryption keys.
*设置加密密钥的存储位置。
* @param string $path
* @return void
public static function loadKeysFrom ($path)
static::$keyPath = $path;
* The location of the encryption keys.
*加密密钥的位置。
* @param string $file
* @return string
public static function keyPath ($file)
$file = ltrim ($file, '/\\');
return static::$keyPath
? rtrim (static::$keyPath, '/\\') . DIRECTORY_SEPARATOR . $file
: storage_path ($file);
* Set the auth code model class name.
*设置身份验证代码模型类名称。
* @param string $authCodeModel
* @return void
public static function useAuthCodeModel ($authCodeModel)
static::$authCodeModel = $authCodeModel;
* Get the auth code model class name.
* @return string
public static function authCodeModel ()
return static::$authCodeModel;
* Get a new auth code model instance.
* @return \Laravel\Passport\AuthCode
public static function authCode ()
return new static::$authCodeModel;
* Set the client model class name.
* @param string $clientModel
* @return void
public static function useClientModel ($clientModel)
static::$clientModel = $clientModel;
* Get the client model class name.
* @return string
public static function clientModel ()
return static::$clientModel;
* Get a new client model instance.
* @return \Laravel\Passport\Client
public static function client ()
return new static::$clientModel;
* Set the personal access client model class name.
* @param string $clientModel
* @return void
public static function usePersonalAccessClientModel ($clientModel)
static::$personalAccessClientModel = $clientModel;
* Get the personal access client model class name.
* @return string
public static function personalAccessClientModel ()
return static::$personalAccessClientModel;
* Get a new personal access client model instance.
* @return \Laravel\Passport\PersonalAccessClient
public static function personalAccessClient ()
return new static::$personalAccessClientModel;
* Set the token model class name.
* @param string $tokenModel
* @return void
public static function useTokenModel ($tokenModel)
static::$tokenModel = $tokenModel;
* Get the token model class name.
* @return string
public static function tokenModel ()
return static::$tokenModel;
* Get a new personal access client model instance.
* @return \Laravel\Passport\Token
public static function token ()
return new static::$tokenModel;
* Configure Passport to not register its migrations.
* @return static
public static function ignoreMigrations ()
static::$runsMigrations = false;
return new static;
* Instruct Passport to enable cookie serialization.
* @return static
public static function withCookieSerialization ()
static::$unserializesCookies = true;
return new static;
* Instruct Passport to disable cookie serialization.
* @return static
public static function withoutCookieSerialization ()
static::$unserializesCookies = false;
return new static;
use phpseclib\Crypt\RSA;
ras 生产密钥对
$rsa->createKey ($this->input ? (int) $this->option ('length') : 4096);
命令行操作位置
protected $signature = 'passport:client
{--personal : Create a personal access token client}
{--password : Create a password grant client}
{--client : Create a client credentials grant client}
{--name= : The name of the client}
{--redirect_uri= : The URI to redirect to after authorization }
{--user_id= : The user ID the client should be assigned to }';
public function handle (ClientRepository $clients)
if ($this->option ('personal')) {
$this->createPersonalClient ($clients);
} elseif ($this->option ('password')) {
$this->createPasswordClient ($clients);
} elseif ($this->option ('client')) {
$this->createClientCredentialsClient ($clients);
} else {
$this->createAuthCodeClient ($clients);
拿 personal 实例
public function createPersonalAccessClient ($userId, $name, $redirect)
return tap ($this->create ($userId, $name, $redirect, true), function ($client) {
// 创建好客户端之后,再来创建一个 OAuth_personal_access_clients 这个表,添加刚才的客户端 ID
$accessClient = Passport::personalAccessClient ();
$accessClient->client_id = $client->id;
$accessClient->save ();
public function create ($userId, $name, $redirect, $personalAccess = false, $password = false)
//Laravel\Passport\Client 对应这个表 OAuth_clients
$client = Passport::client ()->forceFill ([
'user_id' =>$userId,
'name' =>$name,
'secret' =>Str::random (40),
'redirect' =>$redirect,
'personal_access_client' =>$personalAccess,
'password_client' =>$password,
'revoked' =>false,
$client->save ();
return $client;
密码创建,就没有多创建个 OAuth_personal_access_clients 这个表,添加刚才的客户端 ID
public function createPasswordGrantClient ($userId, $name, $redirect)
return $this->create ($userId, $name, $redirect, false, true);
题外话 tap,类似回调函数,传递匿名函数和参数
使用给定值调用给定的 Closure,然后返回值。
function tap ($value, $callback = null)
if (is_null ($callback)) {
return new HigherOrderTapProxy ($value);
$callback ($value);
return $value;
自定义迁移
如果你不想使用 Passport 的默认迁移,需要在 AppServiceProvider 的 register 方法中调用 Passport::ignoreMigrations 方法。你可以使用 PHP artisan vendor:publish --tag=passport-migrations
导出默认迁移。
\vendor\Laravel\passport\src\PassportServiceProvider.php
$this->loadViewsFrom (__DIR__.'/../resources/views', 'passport');
$this->deleteCookieOnLogout ();
if ($this->App->runningInConsole ()) {
$this->registerMigrations ();
$this->publishes ([
__DIR__.'/../database/migrations' =>database_path ('migrations'),
], 'passport-migrations');
$this->publishes ([
__DIR__.'/../resources/views' =>base_path ('resources/views/vendor/passport'),
], 'passport-views');
$this->publishes ([
__DIR__.'/../resources/JS/components' =>base_path ('resources/JS/components/passport'),
], 'passport-components');
$this->commands ([
Console\InstallCommand::class,
Console\ClientCommand::class,
Console\KeysCommand::class,
默认路由位置
\vendor\Laravel\passport\src\RouteRegistrar.php
public function all ()
// 授权所需的路线
$this->forAuthorization ();
// 检索和发出访问令牌的路由
$this->forAccessTokens ();
// 刷新令牌
$this->forTransientTokens ();
// 管理客户端所需的路由
$this->forClients ();
// 管理个人访问令牌所需的路由
$this->forPersonalAccessTokens ();
管理客户端
$router->get ('/clients', [
'uses' =>'ClientController@forUser',
'as' =>'passport.clients.index',
public function forUser (Request $request)
$userId = $request->user ()->getKey ();// 取得用户的 id
// 取得该认证后的用户生效的客户端 DI,
return $this->clients->activeForUser ($userId)->makeVisible ('secret');
public function activeForUser ($userId)
return $this->forUser ($userId)->reject (function ($client) {
return $client->revoked;// 如果是真的话,将会被移除
})->values ();
public function forUser ($userId)
return Passport::client ()
->where ('user_id', $userId)
->orderBy ('name', 'asc')->get ();
$collection = collect ([1, 2, 3, 4]);
$filtered = $collection->reject (function ($item) {
return $item >2;
$filtered->all ();
$router->post ('/clients', [
'uses' =>'ClientController@store',
'as' =>'passport.clients.store',
public function store (Request $request)
$this->validation->make ($request->all (), [
'name' =>'required|max:255',
'redirect' =>['required', $this->redirectRule],
])->validate ();
return $this->clients->create (
$request->user ()->getKey (), $request->name, $request->redirect
)->makeVisible ('secret');
->makeVisible ('secret'); 表示显示 secret,尽管你在 secret 也要
$router->put ('/clients/{client_id}', [
'uses' =>'ClientController@update',
'as' =>'passport.clients.update',
public function update (Request $request, $clientId)
$client = $this->clients->findForUser ($clientId, $request->user ()->getKey ());
if (! $client) {
return new Response ('', 404);
$this->validation->make ($request->all (), [
'name' =>'required|max:255',
'redirect' =>['required', $this->redirectRule],
])->validate ();
return $this->clients->update (
$client, $request->name, $request->redirect
public function update (Client $client, $name, $redirect)
$client->forceFill ([
'name' =>$name, 'redirect' =>$redirect,
])->save ();
return $client;
$router->delete ('/clients/{client_id}', [
'uses' =>'ClientController@destroy',
'as' =>'passport.clients.destroy',
Laravel\Passport\Token 对应这个表 OAuth_access_tokens
管理个人访问令牌所需的路由
$router->get ('/scopes', [
'uses' =>'ScopeController@all',
'as' =>'passport.scopes.index',
取得所有的授权访问
public static function scopes ()
return collect (static::$scopes)->map (function ($description, $id) {
return new Scope ($id, $description);
})->values ();
取得个人的 tokens
$router->get ('/personal-access-tokens', [
'uses' =>'PersonalAccessTokenController@forUser',
'as' =>'passport.personal.tokens.index',
public function forUser (Request $request)
$tokens = $this->tokenRepository->forUser ($request->user ()->getKey ());
return $tokens->load ('client')->filter (function ($token) {
return $token->client->personal_access_client && ! $token->revoked;
})->values ();
// 最后返回所有的 token 表数据,然后关联了客户端表,判断客户端是否无效,无效的话过滤掉,然后最后返回
public function client ()
return $this->belongsTo (Passport::clientModel ());
public function forUser ($userId)
return Passport::token ()->where ('user_id', $userId)->get ();
$router->post ('/personal-access-tokens', [
'uses' =>'PersonalAccessTokenController@store',
'as' =>'passport.personal.tokens.store',
public function store (Request $request)
$this->validation->make ($request->all (), [
'name' =>'required|max:255',
'scopes' =>'array|in:'.implode (',', Passport::scopeIds ()),
])->validate ();
return $request->user ()->createToken (
$request->name, $request->scopes ?: []
$router->delete ('/personal-access-tokens/{token_id}', [
'uses' =>'PersonalAccessTokenController@destroy',
'as' =>'passport.personal.tokens.destroy',
public function destroy (Request $request, $tokenId)
$token = $this->tokenRepository->findForUser (
$tokenId, $request->user ()->getKey ()
if (is_null ($token)) {
return new Response ('', 404);
$token->revoke ();
return new Response ('', Response::HTTP_NO_CONTENT);
public function findForUser ($id, $userId)
return Passport::token ()->where ('id', $id)->where ('user_id', $userId)->first ();
public function revoke ()
return $this->forceFill (['revoked' =>true])->save ();
return (new Response ('Refreshed.'))->withCookie ($this->cookieFactory->make (
$request->user ()->getKey (), $request->session ()->token ()
检索和发出访问令牌的路由
// 授权客户端访问用户的帐户
$this->router->post ('/token', [
'uses' =>'AccessTokenController@issueToken',
'as' =>'passport.token',
'middleware' =>'throttle',
$router->get ('/tokens', [
'uses' =>'AuthorizedAccessTokenController@forUser',
'as' =>'passport.tokens.index',
public function forUser (Request $request)
$tokens = $this->tokenRepository->forUser ($request->user ()->getKey ());
return $tokens->load ('client')->filter (function ($token) {
return ! $token->client->firstParty () && ! $token->revoked;
})->values ();
$router->delete ('/tokens/{token_id}', [
'uses' =>'AuthorizedAccessTokenController@destroy',
'as' =>'passport.tokens.destroy',
public function destroy (Request $request, $tokenId)
$token = $this->tokenRepository->findForUser (
$tokenId, $request->user ()->getKey ()
if (is_null ($token)) {
return new Response ('', 404);
$token->revoke ();
return new Response ('', Response::HTTP_NO_CONTENT);
$this->router->group (['middleware' =>['Web', 'auth']], function ($router) {
$router->get ('/authorize', [
'uses' =>'AuthorizationController@authorize',
'as' =>'passport.authorizations.authorize',
$router->post ('/authorize', [
'uses' =>'ApproveAuthorizationController@approve',
'as' =>'passport.authorizations.approve',
$router->delete ('/authorize', [
'uses' =>'DenyAuthorizationController@deny',
'as' =>'passport.authorizations.deny',
public function authorize (ServerRequestInterface $psrRequest,
Request $request,
ClientRepository $clients,
TokenRepository $tokens)
return $this->withErrorHandling (function () use ($psrRequest, $request, $clients, $tokens) {
$authRequest = $this->server->validateAuthorizationRequest ($psrRequest);
$scopes = $this->parseScopes ($authRequest);
$token = $tokens->findValidToken (
$user = $request->user (),
$client = $clients->find ($authRequest->getClient ()->getIdentifier ())
if ($token && $token->scopes === collect ($scopes)->pluck ('id')->all ()) {
return $this->approveRequest ($authRequest, $user);
$request->session ()->put ('authRequest', $authRequest);
return $this->response->view ('passport::authorize', [
'client' =>$client,
'user' =>$user,
'scopes' =>$scopes,
'request' =>$request,
$router->post ('/authorize', [
'uses' =>'ApproveAuthorizationController@approve',
'as' =>'passport.authorizations.approve',
1.除了标识原创之外,其他可能来源于网友的分享,仅供学习使用
2.如您发现侵犯了您的权利,请联系我们删除
3.转载必须带本文链接,否则你将侵权
4.关于会员或其发布的相关内容均由会员自行提供,会员依法应对其提供的任何信息承担全部责任,本站不对此承担任何法律责任