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

12 声望
1 粉丝
0 条评论
推荐阅读
flex布局中的flex-basis,flex-grow,flex-shrink到底咋回事儿?
flex布局是非常强大的布局方式,它能轻易完成我们能想到的大部分布局,类似圣杯布局、双飞翼布局等等,它非常灵活,兼容性也很好,在项目中经常被使用到。大多数同学应该都是从阮一峰老师的 这篇博文 了解到flex...

唔系我认叻阅读 680

One 一个简洁的博客、微博客系统
代码:[链接]文档:[链接]系统预览首页:微博列表:微博详细:文章列表:文章详细:归档:搜索,目前只能依据分类、标签搜索😀:管理后台:

Eyeswap45阅读 2.3k评论 1

怎样用 PHP 来实现枚举?
在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。枚举是一个被命名的整型常数的集合,枚举在日常生活中很常见,...

唯一丶25阅读 6.4k评论 4

PHP转Go实践:xjson解析神器「开源工具集」
我和劲仔都是PHP转Go,身边越来越多做PHP的朋友也逐渐在用Go进行重构,重构过程中,会发现php的json解析操作(系列化与反序列化)是真的香,弱类型语言的各种隐式类型转换,很大程度的减低了程序的复杂度。

王中阳Go10阅读 2k评论 3

封面图
图片防盗链破解 解决图片防盗链问题 反向代理
当客户端(浏览器)向服务器请求内容的时候,会提交一个header,这个header中包含了如:浏览器信息、cookie等内容,那么有一个叫referer的东东,也包含在这里面。

TANKING7阅读 11.3k评论 5

Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go5阅读 2.3k评论 2

封面图
Hyperf 3.0 发布,PHP 新时代
在过去的一年半时间里,Hyperf 2.2 共发布了 35 个小版本,使 Hyperf 达到了一个前所未有的高度,这里也获得了一些不错的数据反馈。

huangzhhui4阅读 1.1k评论 1

封面图
12 声望
1 粉丝
宣传栏