laravel passport 的 oauth2机制(二)—— 源码解读
唔系我认叻 -如果已经理解oauth2.0原理,也安装后laravel passport的情况下。现在从源码中看看相关的逻辑流程,是如何走的。
在这之前我们先看下laravel如何判断http客户端请求是普通请求,还是json请求,因为passport 默认是api json请求的。
\vendor\laravel\framework\src\Illuminate\Http\Concerns\InteractsWithContentTypes.php 判断http header 的 Accept 是否带有json或+json。
public function expectsJson()
{
return ($this->ajax() && ! $this->pjax() && $this->acceptsAnyContentType()) || $this->wantsJson();
}
public function wantsJson()
{
$acceptable = $this->getAcceptableContentTypes();
return isset($acceptable[0]) && Str::contains($acceptable[0], ['/json', '+json']);
}
知道请求方法后,我们看看如何获取oauth access_token。用php artisan route:list 可以查看到 这条记录
POST| oauth/token| passport.token|Laravel\Passport\Http\Controllers\AccessTokenController@issueToken
后期进入代码查看,\vendor\laravel\passport\src\Http\Controllers\AccessTokenController.php,再进入respondToAccessTokenRequest 这个方法,而respondToAccessTokenRequest 这个方法又是在league 这个库中。没错,passport的验证方法是引用league 的oauth2-server。
public function issueToken(ServerRequestInterface $request)
{
return $this->withErrorHandling(function () use ($request) {
return $this->convertResponse(
$this->server->respondToAccessTokenRequest($request, new Psr7Response)
);
});
}
现在我们进去看看 vendor\league\oauth2-server\src\AuthorizationServer.php
public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseInterface $response)
{
foreach ($this->enabledGrantTypes as $grantType) {
//print_r($grantType);exit;
if (!$grantType->canRespondToAccessTokenRequest($request)) {
continue;
}
$tokenResponse = $grantType->respondToAccessTokenRequest(
$request,
$this->getResponseType(),
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()]
);
if ($tokenResponse instanceof ResponseTypeInterface) {
return $tokenResponse->generateHttpResponse($response);
}
}
throw OAuthServerException::unsupportedGrantType();
}
这里解读下
循环grant形式(授权码模式、简化模式、密码模式、客户端模式)根据用户请求的grant类型进行生成access_toekn操作,如果不是的就continue掉respondToAccessTokenRequest是接口,分别有grant不同grant形式去实现,本文例子用password (\vendor\league\oauth2-server\src\Grant\PasswordGrant.php)生成token直接返回,如果有问题就抛异常我们再到PasswordGrant这里看看
public function respondToAccessTokenRequest(
ServerRequestInterface $request,
ResponseTypeInterface $responseType,
DateInterval $accessTokenTTL
) {
// Validate request
$client = $this->validateClient($request);
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request, $this->defaultScope));
$user = $this->validateUser($request, $client);
// Finalize the requested scopes
$finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
// Issue and persist new access token
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $finalizedScopes);
$this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
$responseType->setAccessToken($accessToken);
// Issue and persist new refresh token if given
$refreshToken = $this->issueRefreshToken($accessToken);
if ($refreshToken !== null) {
$this->getEmitter()->emit(new RequestRefreshTokenEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request, $refreshToken));
$responseType->setRefreshToken($refreshToken);
}
return $responseType;
}
这里比较重点就是这3个验证,分别是整体传过来的客户端数据格式验证,之后是oauth scope权限验证,跟着就是根据账号密码查数据库用户验证
$client = $this->validateClient($request);
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request, $this->defaultScope));
$user = $this->validateUser($request, $client);
直到这里我们laravel passport整个oauth2 生成access_token的核心逻辑代码流程已经完成了。后面我们看看在中间件中他们是判断token的合法性
在routes.php看到中间件是auth:api
Route::middleware('auth:api')->get('/user', function (Request $request) {
echo 'hello world';
});
主要是这个文件vendor\laravel\framework\src\Illuminate\Auth\Middleware\Authenticate.php authenticate 这个方法,参数grauds就是接收:api这个参数,这个参数会变成config 下auth.php的passport去解密验证,这个逻辑就在\vendor\laravel\framework\src\Illuminate\Auth\AuthManager.php guard()这个方法里面
protected function authenticate($request, array $guards)
{
if (empty($guards)) {
$guards = [null];
}
foreach ($guards as $guard) {
if ($this->auth->guard($guard)->check()) {
return $this->auth->shouldUse($guard);
}
}
$this->unauthenticated($request, $guards);
}
这里就从生成到验证整个passport oauth2的过程了。
参考
https://www.cntofu.com/book/107/Laravel%20Passport%E2%80%94%E2%80%94OAuth2%20API%20%E8%AE%A4%E8%AF%81%E7%B3%BB%E7%BB%9F%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90%EF%BC%88%E4%B8%8B%EF%BC%89.md
php介绍
PHP即“超文本预处理器”,是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。利于学习,使用广泛,主要适用于Web开发领域。