乐趣区

关于php: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

退出移动版