<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Zhou Hiro on Medium]]></title>
        <description><![CDATA[Stories by Zhou Hiro on Medium]]></description>
        <link>https://medium.com/@zxishere?source=rss-8d1ed6a02e1d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*_B9Kgttiz-Qm1Tkn.</url>
            <title>Stories by Zhou Hiro on Medium</title>
            <link>https://medium.com/@zxishere?source=rss-8d1ed6a02e1d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 12:23:54 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@zxishere/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[基于Laravel Passport API 的多用户多字段认证系统（三）：多字段登录]]></title>
            <link>https://medium.com/@zxishere/%E5%9F%BA%E4%BA%8Elaravel-passport-api-%E7%9A%84%E5%A4%9A%E7%94%A8%E6%88%B7%E5%A4%9A%E5%AD%97%E6%AE%B5%E8%AE%A4%E8%AF%81%E7%B3%BB%E7%BB%9F-%E4%B8%89-ed4300513acf?source=rss-8d1ed6a02e1d------2</link>
            <guid isPermaLink="false">https://medium.com/p/ed4300513acf</guid>
            <category><![CDATA[curl]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[laravel]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[oauth2]]></category>
            <dc:creator><![CDATA[Zhou Hiro]]></dc:creator>
            <pubDate>Fri, 05 Jan 2018 02:42:06 GMT</pubDate>
            <atom:updated>2018-01-05T02:58:01.024Z</atom:updated>
            <content:encoded><![CDATA[<h3>3. 多字段登录</h3><p>传统意义的多字段登录，是通过 userid 或 username 或 email 这类任意一个 <strong>unique </strong>字段+密码验证。例如京东：</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/335/1*I6ZqAlbCX4ymeEcrOdNfIQ.png" /></figure><p>通过 Laravel Passport 自带的 findForPassport ，做一点小小的修改即可完全满足：</p><pre>public function findForPassport($username) {<br>  return $this-&gt;orWhere(&#39;email&#39;, $username)-&gt;orWhere(&#39;phone&#39;, $username)-&gt;first();<br> }</pre><p>对于一些特殊的固定字段，例如用户是否激活，也可以采用以下方式做验证，参见 <a href="https://github.com/laravel/passport/issues/81">Issue</a>：</p><pre>public function findForPassport($username)<br>    {<br>        $user = $this-&gt;where(&#39;email&#39;, $username)-&gt;first();<br><br>        if($user !== null &amp;&amp; $user-&gt;status == 0) {<br>            throw new OAuthServerException(&#39;User account is not activated&#39;, 6, &#39;account_inactive&#39;, 401);<br>        }<br>        return $user;<br>    }</pre><p>但是，如果想<strong>同时</strong>满足多个字段的验证，例如上一章的 Student ，必须同时满足 school_id 和 student_no 的条件</p><pre>Student::create([<br>   &#39;school_id&#39;  =&gt; &#39;10001&#39;,<br>   &#39;student_no&#39; =&gt; &#39;17000003001&#39;,<br>   &#39;name&#39;       =&gt; &#39;Abbey&#39;,<br>   &#39;password&#39;   =&gt; bcrypt(&#39;st001&#39;)<br>        ]);</pre><p>因为 findForPassport 默认只传递了一个 username 的字段，因此还是需要自己扩展。并且我也想可以自定义字段名，不一定必须使用username。</p><p>以下部分代码参考了<a href="https://laravel-china.org/users/32">@Ryan</a> 的 <a href="https://laravel-china.org/articles/5548/brief-summary-of-laravel-passport-api-certification">Laravel Passport API 认证使用小结</a>，特别表示感谢。</p><p>上一章已经定位到了源码的 vendor/league/oauth2-server/src/Grant/<strong>PasswordGrant</strong>.php，有一个<strong>validateUserd</strong>的函数调用了<strong>getUserEntityByUserCredentials</strong>。</p><pre>protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)<br>    {<br>        $username = $this-&gt;getRequestParameter(&#39;username&#39;, $request);<br>        if (is_null($username)) {<br>            throw OAuthServerException::invalidRequest(&#39;username&#39;);<br>        }</pre><pre>$password = $this-&gt;getRequestParameter(&#39;password&#39;, $request);<br>        if (is_null($password)) {<br>            throw OAuthServerException::invalidRequest(&#39;password&#39;);<br>        }</pre><pre>$user = $this-&gt;userRepository-&gt;getUserEntityByUserCredentials(<br>            $username,<br>            $password,<br>            $this-&gt;getIdentifier(),<br>            $client<br>        );<br>        if ($user instanceof UserEntityInterface === false) {<br>            $this-&gt;getEmitter()-&gt;emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));</pre><pre>throw OAuthServerException::invalidCredentials();<br>        }</pre><pre>return $user;<br>    }</pre><p>因此，需要先把<strong>PasswordGrant</strong>扩展出来。</p><p>3.1 在App\Auth新建PasswordGrant.php，代码如下：</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/175a2e9f975be1fe17ec053f999ac417/href">https://medium.com/media/175a2e9f975be1fe17ec053f999ac417/href</a></iframe><p>主要改动逻辑为：<br>如果传递的参数有provider，则为多用户登录，不用强制验证username了。<br>当然这里也可以加更多逻辑，按照实际需求来。</p><pre>$provider = $this-&gt;getRequestParameter(&#39;provider&#39;, $request);<br>if(is_null($provider) &amp;&amp; is_null($username)){<br>    throw OAuthServerException::invalidRequest(&#39;username&#39;);<br>}</pre><p>3.2 还需要扩展 vendor/laravel/passport/src/Bridge/UserRepository.php 里面的 getUserEntityByUserCredentials，在App\Auth新建MuitiAuthPassportRepository.php，代码如下：</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/333cb71f9ac0ca0f116f5b9bc2ea8e7f/href">https://medium.com/media/333cb71f9ac0ca0f116f5b9bc2ea8e7f/href</a></iframe><p>验证传递参数的时候，如果模型里面存在自定义的 findForPassportMulti 函数，则把所有的 Request 都传递进去，再多字段也不怕！！！</p><pre>if (method_exists($model, &#39;findForPassport&#39;)) {<br>            $user = (new $model)-&gt;findForPassport($username);<br>        } else {<br>            if (method_exists($model, &#39;findForPassportMulti&#39;)) {<br>                $user = (new $model)-&gt;findForPassportMulti(App::make(Request::class)-&gt;all());<br>            }else{<br>                $user = (new $model)-&gt;where(&#39;email&#39;, $username)-&gt;first();<br>            }<br>        }</pre><p>3.3 修改Student Model：</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8aaa1aac0868f542b06ad8417b08fefc/href">https://medium.com/media/8aaa1aac0868f542b06ad8417b08fefc/href</a></iframe><p>把所有的 Request 都传递进去以外，应该还有一种更优雅的实现逻辑，参考 <a href="https://segmentfault.com/a/1190000011099346">Laravel 用户多字段认证优雅解决方案</a>。</p><p>3.4 在 App\Providers 新建 PassportServiceProvider.php，引入上面的扩展</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0abfc5a1a32cb7d010fc727705c8a6c8/href">https://medium.com/media/0abfc5a1a32cb7d010fc727705c8a6c8/href</a></iframe><p>这个 PassportServiceProvider 继承了 Passport 原有的 PassportServiceProvider，需要手动加入 config/app.php的providers配置段中：</p><pre>&#39;providers&#39; =&gt; [<br>        ...<br>         * Application Service Providers...<br>         */<br>        App\Providers\AppServiceProvider::class,<br>        App\Providers\AuthServiceProvider::class,<br>        // App\Providers\BroadcastServiceProvider::class,<br>        App\Providers\EventServiceProvider::class,<br>        App\Providers\RouteServiceProvider::class,<br>        App\Providers\PassportServiceProvider::class,<br>    ],</pre><p>测试一下多字段的登录，正常返回Token.：</p><pre>curl --request POST \<br>  --url <a href="http://multiauth.test/oauth/token">http://multiauth.test/oauth/token</a> \<br>  --header &#39;accept: application/json&#39; \<br>  --header &#39;content-type: application/x-www-form-urlencoded&#39; \<br>  --data &#39;school_id=10001&amp;student_no=17000003001&amp;password=st001&amp;client_id=2&amp;client_secret=secret&amp;grant_type=password&amp;scope=&amp;provider=students&#39;</pre><p>如果少传一个字段student_no：</p><pre>curl --request POST \<br>  --url <a href="http://multiauth.test/oauth/token">http://multiauth.test/oauth/token</a> \<br>  --header &#39;accept: application/json&#39; \<br>  --header &#39;content-type: application/x-www-form-urlencoded&#39; \<br>  --data &#39;school_id=10001&amp;password=st001&amp;client_id=2&amp;client_secret=secret&amp;grant_type=password&amp;scope=&amp;provider=students&#39;</pre><p>则妥妥的报错：Undefined index: student_no</p><p>Laravel的异常抛出有更优雅的实现方式，不在本文讨论范围内。</p><p>至此，多字段登录的功能也实现了。</p><p>下一章讲解退出登录以及通过Middleware限制访问。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ed4300513acf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[基于Laravel Passport API 的多用户多字段认证系统（二）：多用户登录]]></title>
            <link>https://medium.com/@zxishere/%E5%9F%BA%E4%BA%8Elaravel-passport-api-%E7%9A%84%E5%A4%9A%E7%94%A8%E6%88%B7%E5%A4%9A%E5%AD%97%E6%AE%B5%E8%AE%A4%E8%AF%81%E7%B3%BB%E7%BB%9F-%E4%BA%8C-9c12cfb9edd4?source=rss-8d1ed6a02e1d------2</link>
            <guid isPermaLink="false">https://medium.com/p/9c12cfb9edd4</guid>
            <category><![CDATA[laravel]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[oauth2]]></category>
            <category><![CDATA[curl]]></category>
            <dc:creator><![CDATA[Zhou Hiro]]></dc:creator>
            <pubDate>Thu, 04 Jan 2018 14:48:59 GMT</pubDate>
            <atom:updated>2018-01-05T02:59:06.484Z</atom:updated>
            <content:encoded><![CDATA[<h3>2. 扩展多用户登录</h3><p>多用户登录在Passport的 <a href="https://github.com/laravel/passport/issues/161">这个Issue</a> 里面有非常多的讨论，其他网站例如stackoverflow的诸多问题最后还是回到了这个Issue。<br>有一位叫做 <a href="https://github.com/sfelix-martins">sfelix-martins</a> 的热心群众已经开发了 <a href="https://github.com/sfelix-martins/passport-multiauth">扩展包passport-multiauth</a>。实现原理为Issue里面提及的，通过增加一张 oauth_access_token_providers 的扩展表。用户第一次登录，通过 &quot;provider&quot;参数传递需要关联的模型。以后每次通过Token传参时，在middleware里面做一层验证，把Token对应到相应的模型。不传 &quot;provider&quot;则默认为User模型。<br>有现成的轮子省了不少事，话不多说，直接开撸。</p><p>2–1. 引入multiauth扩展包</p><pre>composer require smartins/passport-multiauth</pre><p>2–2. 以老师和学生为例, 创建数据表。未使用常见的username字段。</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1779028b7054ce4aa02782be8d0bd7b0/href">https://medium.com/media/1779028b7054ce4aa02782be8d0bd7b0/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2d95c76d391c7498e9ccb99ebc791717/href">https://medium.com/media/2d95c76d391c7498e9ccb99ebc791717/href</a></iframe><p>并且在项目的app\Models文件夹，参考User, 建立对应的测试模型。</p><pre>&lt;?php</pre><pre>namespace App\Models;</pre><pre>use Laravel\Passport\HasApiTokens;<br>use Illuminate\Notifications\Notifiable;<br>use Illuminate\Foundation\Auth\User as Authenticatable;</pre><pre>class Student extends Authenticatable<br>{<br>    use HasApiTokens, Notifiable;</pre><pre>protected $fillable = [<br>        &#39;school_id&#39;, &#39;student_no&#39;, &#39;password&#39;,<br>    ];</pre><pre>protected $hidden = [<br>        &#39;password&#39;<br>    ];</pre><pre>}</pre><pre>&lt;?php</pre><pre>namespace App\Models;</pre><pre>use Laravel\Passport\HasApiTokens;<br>use Illuminate\Notifications\Notifiable;<br>use Illuminate\Foundation\Auth\User as Authenticatable;</pre><pre>class Teacher extends Authenticatable<br>{<br>    use HasApiTokens, Notifiable;</pre><pre>protected $fillable = [<br>        &#39;school_id&#39;, &#39;password&#39;,<br>    ];</pre><pre>protected $hidden = [<br>        &#39;password&#39;<br>    ];</pre><pre>}</pre><p>2–3. 数据表迁移</p><pre>php artisan migrate</pre><p>2–4. 老惯例，需要增加测试数据，建立Seeder文件并且导入</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3e22a631faa4791a3dde5ec705bc42db/href">https://medium.com/media/3e22a631faa4791a3dde5ec705bc42db/href</a></iframe><pre>composer dump-autoload</pre><pre>php artisan db:seed --class=StudentsAndTeacherSeeder</pre><p>2–5. 配置文件 config/auth.php 中 providers 数组增加对应的模型</p><pre>&#39;providers&#39; =&gt; [<br>        &#39;users&#39; =&gt; [<br>            &#39;driver&#39; =&gt; &#39;eloquent&#39;,<br>            &#39;model&#39; =&gt; App\User::class,<br>        ],</pre><pre>&#39;students&#39; =&gt; [<br>            &#39;driver&#39; =&gt; &#39;eloquent&#39;,<br>            &#39;model&#39; =&gt; App\Models\Student::class,<br>        ],</pre><pre>&#39;teachers&#39; =&gt; [<br>            &#39;driver&#39; =&gt; &#39;eloquent&#39;,<br>            &#39;model&#39; =&gt; App\Models\Teacher::class,<br>        ],</pre><pre>],</pre><p>2–6. 在文件 app/Http/Kernelmiddlewares 的$middlewareGroups中，注册自定义的PassportCustomProvider 和PassportCustomProviderAccessToken 。</p><pre>class Kernel extends HttpKernel<br>{<br>    ...</pre><pre>    /**<br>     * The application&#39;s route middleware groups.<br>     *<br>     * @var array<br>     */<br>    protected $middlewareGroups = [<br>        &#39;web&#39; =&gt; [<br>            \App\Http\Middleware\EncryptCookies::class,<br>            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,<br>            \Illuminate\Session\Middleware\StartSession::class,<br>            // \Illuminate\Session\Middleware\AuthenticateSession::class,<br>            \Illuminate\View\Middleware\ShareErrorsFromSession::class,<br>            \App\Http\Middleware\VerifyCsrfToken::class,<br>            \Illuminate\Routing\Middleware\SubstituteBindings::class,<br>        ],</pre><pre>        &#39;api&#39; =&gt; [<br>            &#39;throttle:60,1&#39;,<br>            &#39;bindings&#39;,<br>            \Barryvdh\Cors\HandleCors::class,<br>            &#39;custom-provider&#39;,<br>        ],</pre><pre>        &#39;custom-provider&#39; =&gt; [<br>            \SMartins\PassportMultiauth\Http\Middleware\AddCustomProvider::class,<br>            \SMartins\PassportMultiauth\Http\Middleware\ConfigAccessTokenCustomProvider::class,<br>        ]<br>    ];</pre><pre>    ...<br>}</pre><p>2–7. 在 AuthServiceProvider 增加 access token 对应的 passport routes。</p><pre>use Route;<br>use Laravel\Passport\Passport;</pre><pre>class AuthServiceProvider extends ServiceProvider<br>{<br>    ...<br>    <br>    /**<br>     * Register any authentication / authorization services.<br>     *<br>     * @return void<br>     */<br>    public function boot()<br>    {<br>        $this-&gt;registerPolicies();</pre><pre>        Passport::routes();</pre><pre>        Route::group([&#39;middleware&#39; =&gt; &#39;api&#39;], function () {<br>            Passport::routes(function ($router) {<br>                return $router-&gt;forAccessTokens();<br>            });<br>        });<br>    }<br>    ...<br>}</pre><p>2–8. 先测试下Teacher的登录，帐号和密码参照Seeder。</p><p>这是最常见的ID和密码登录方式，用户名或手机号或邮箱登录均类似。<br>按照文档，需要在参数里面增加provider=<strong>teachers</strong>，对应上面2–4.</p><pre>curl --request POST \<br>  --url <a href="http://multiauth.test/oauth/token"><strong>http://multiauth.test</strong>/oauth/token</a> \<br>  --header &#39;accept: application/json&#39; \<br>  --header &#39;content-type: application/x-www-form-urlencoded&#39; \<br>  --data &#39;school_id=10001&amp;password=tt111&amp;client_id=2&amp;client_secret=<strong>secret</strong>&amp;grant_type=password&amp;scope=&amp;provider=teachers&#39;</pre><p>不出意外，可以看见以下的结果</p><pre>{&quot;error&quot;:&quot;invalid_request&quot;,&quot;message&quot;:&quot;The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.&quot;,&quot;hint&quot;:&quot;Check the `username` parameter&quot;}</pre><p>既然一定要username，那我把school_id换成username试试：</p><pre>curl --request POST \<br>  --url <a href="http://multiauth.test/oauth/token"><strong>http://multiauth.test</strong>/oauth/token</a> \<br>  --header &#39;accept: application/json&#39; \<br>  --header &#39;content-type: application/x-www-form-urlencoded&#39; \<br>  --data &#39;username=10001&amp;password=tt111&amp;client_id=2&amp;client_secret=<strong>secret</strong>&amp;grant_type=password&amp;scope=&amp;provider=teachers&#39;</pre><p>然鹅，还是报错登陆不上，因为数据结构里面压根就没有username这个字段啊。另外冒出来的email是什么东西。</p><pre>SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘email’ in ‘where clause’ (SQL: select * from `teachers` where `email` = 10001 limit 1)</pre><p>What the f….算了，还是先查下网上有没有类似的问题吧。<br>在 <a href="https://github.com/laravel/passport/issues/81">这个Issue</a> 里面，有人提出了一个简单的解决方案，使用官方文档中并未提及的 findForPassport函数。这个函数会把username映射为需要匹配的unique字段。既然都到这一步了，那还是追一下源码吧，在vendor/laravel/passport/src/Bridge/UserRepository.php 的41行，出现了这个函数。</p><pre>if (method_exists($model, &#39;findForPassport&#39;)) {<br>            $user = (new $model)-&gt;findForPassport($username);<br>        } else {<br>            $user = (new $model)-&gt;where(&#39;email&#39;, $username)-&gt;first();<br>        }</pre><p>如果在model里面存在findForPassport这个函数，则返回对应的model。<br>如果不存在，则去取email字段。因为我的Teacher表也没有email字段，所以报错 Unknown column ‘email’ 。</p><p>这段代码隶属于getUserEntityByUserCredentials这个函数，那哪里又调用了这个函数呢？ 继续阅读源码+1.<br>在 vendor/league/oauth2-server/src/Grant/PasswordGrant.php，有一个validateUserd的函数调用了getUserEntityByUserCredentials。<br><strong>并且username是写死的！！！</strong></p><p>所以如果前端不传username，直接抛出invalidRequest异常，对应前面的 ”hint”:”Check the `username` parameter”</p><pre>protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)<br>    {<br>        $username = $this-&gt;getRequestParameter(&#39;username&#39;, $request);<br>        if (is_null($username)) {<br>            throw OAuthServerException::invalidRequest(&#39;username&#39;);<br>        }</pre><pre>$password = $this-&gt;getRequestParameter(&#39;password&#39;, $request);<br>        if (is_null($password)) {<br>            throw OAuthServerException::invalidRequest(&#39;password&#39;);<br>        }</pre><pre>$user = $this-&gt;userRepository-&gt;getUserEntityByUserCredentials(<br>            $username,<br>            $password,<br>            $this-&gt;getIdentifier(),<br>            $client<br>        );</pre><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/766b01e7949ed02c967201ce4d2cea00/href">https://medium.com/media/766b01e7949ed02c967201ce4d2cea00/href</a></iframe><p>老老实实的按照Issues修改model，再次测试，前端必须传递username。</p><pre>curl --request POST \<br>  --url <a href="http://multiauth.test/oauth/token"><strong>http://multiauth.test</strong>/oauth/token</a> \<br>  --header &#39;accept: application/json&#39; \<br>  --header &#39;content-type: application/x-www-form-urlencoded&#39; \<br>  --data &#39;username=10001&amp;password=tt111&amp;client_id=2&amp;client_secret=<strong>secret</strong>&amp;grant_type=password&amp;scope=&amp;provider=teachers&#39;</pre><p>现在可以成功登录，获取Teacher 的 Token了</p><pre>{“token_type”:”Bearer”,”expires_in”:31536000,”access_token”:”eyJ0e...&quot;,”refresh_token”:”def50...”}</pre><p>通过Token获取模型也很简单，传递 ‘api’ guard 到 user()即可。<br>修改app\routes\api.php如下：</p><pre>use Illuminate\Http\Request;</pre><pre>Route::get(&#39;/user&#39;, function (Request $request) {<br>    return $request-&gt;user(&#39;api&#39;);<br>});</pre><p>curl 测试</p><pre>curl -X GET -H &quot;Accept: application/json&quot; -H &quot;Authorization: Bearer eyJ0eX...&quot; <a href="http://multiauth.test/api/user"><strong>http://multiauth.test</strong>/api/user</a></pre><p>成功获取到Teacher信息</p><pre>{&quot;id&quot;:1,&quot;school_id&quot;:&quot;10001&quot;,&quot;teacher_name&quot;:&quot;Kathy&quot;,&quot;created_at&quot;:&quot;2018-01-04 21:26:44&quot;,&quot;updated_at&quot;:&quot;2018-01-04 21:26:44&quot;}</pre><p>如果使用1–10获取到的User的Token去访问相同的 api/user，会返回User的数据。 至此多用户登录基本成功。</p><p>下一章： <a href="https://medium.com/@zxishere/%E5%9F%BA%E4%BA%8Elaravel-passport-api-%E7%9A%84%E5%A4%9A%E7%94%A8%E6%88%B7%E5%A4%9A%E5%AD%97%E6%AE%B5%E8%AE%A4%E8%AF%81%E7%B3%BB%E7%BB%9F-%E4%B8%89-ed4300513acf">基于Laravel Passport API 的多用户多字段认证系统（三）：多字段登录</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9c12cfb9edd4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[基于Laravel Passport API 的多用户多字段认证系统（一）：基础框架搭建]]></title>
            <link>https://medium.com/@zxishere/%E5%9F%BA%E4%BA%8Elaravel-passport-api-%E7%9A%84%E5%A4%9A%E7%94%A8%E6%88%B7%E5%A4%9A%E5%AD%97%E6%AE%B5%E8%AE%A4%E8%AF%81%E7%B3%BB%E7%BB%9F-%E4%B8%80-f98881d20092?source=rss-8d1ed6a02e1d------2</link>
            <guid isPermaLink="false">https://medium.com/p/f98881d20092</guid>
            <category><![CDATA[oauth2]]></category>
            <category><![CDATA[curl]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[laravel]]></category>
            <dc:creator><![CDATA[Zhou Hiro]]></dc:creator>
            <pubDate>Thu, 04 Jan 2018 14:21:54 GMT</pubDate>
            <atom:updated>2018-01-05T02:58:37.245Z</atom:updated>
            <content:encoded><![CDATA[<p>网上关于<a href="https://d.laravel-china.org/docs/5.5/passport">Laravel Passport</a>的教程不少，实际业务需求需要用到多用户多字段登录，原生的Passport包已经无法满足需求。经过查找资料和阅读源码，以下演示基于Laravel 5.5框架全新搭建一套<a href="https://github.com/zxishere/multiauth">API多用户多字段认证的系统Demo</a>。</p><h3><strong>1. 基础框架搭建</strong></h3><p>1-1. 新建Laravel项目，我这里命名为 multiauth</p><pre>composer create-project --prefer-dist laravel/laravel multiauth</pre><p>1-2. 进入文件夹，引入Laravel Passport</p><pre>composer require laravel/passport</pre><p>1-3. 因为Laravel5.5自带了package discover, 因此<strong>无需按照文档中提及的将 Passport 的服务提供者注册到配置文件 config/app.php 的 providers</strong>。直接执行下一步即可：</p><pre>php artisan migrate</pre><p>1-4. 运行 passport:install 命令来创建生成安全访问令牌时所需的加密密钥，同时，这条命令也会创建用于生成访问令牌的「个人访问」客户端和「密码授权」客户端,。<br><strong>请记住 Client ID: 2 对应的 Client Secret ，后续测试需要使用。</strong></p><pre>php artisan passport:install</pre><p>1–5. 将 Laravel\Passport\HasApiTokens Trait 添加到 App\User 模型中，这个 Trait 会给你的模型提供一些辅助函数，用于检查已认证用户的令牌和使用范围：</p><pre>&lt;?php</pre><pre>namespace App;</pre><pre>use Laravel\Passport\HasApiTokens;<br>use Illuminate\Notifications\Notifiable;<br>use Illuminate\Foundation\Auth\User as Authenticatable;</pre><pre>class User extends Authenticatable<br>{<br>    use HasApiTokens, Notifiable;</pre><pre>...</pre><p>1–6. 在 AuthServiceProvider 的 boot 方法中调用 Passport::routes 函数。这个函数会注册发出访问令牌并撤销访问令牌、客户端和个人访问令牌所必需的路由：</p><pre>&lt;?php</pre><pre>namespace App\Providers;</pre><pre>use Laravel\Passport\Passport;<br>use Illuminate\Support\Facades\Gate;<br>use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;</pre><pre>class AuthServiceProvider extends ServiceProvider<br>{<br>    /**<br>     * 应用程序的策略映射。<br>     *<br>     * @var array<br>     */<br>    protected $policies = [<br>        &#39;App\Model&#39; =&gt; &#39;App\Policies\ModelPolicy&#39;,<br>    ];</pre><pre>    /**<br>     * Register any authentication / authorization services.<br>     *<br>     * @return void<br>     */<br>    public function boot()<br>    {<br>        $this-&gt;registerPolicies();</pre><pre>        Passport::routes();<br>    }<br>}</pre><p>1–7. 将配置文件 config/auth.php 中授权看守器 guards 的 api 的 driver 选项改为 passport。此调整会让你的应用程序在在验证传入的 API 的请求时使用 Passport 的 TokenGuard 来处理：</p><pre>&#39;guards&#39; =&gt; [<br>    &#39;web&#39; =&gt; [<br>        &#39;driver&#39; =&gt; &#39;session&#39;,<br>        &#39;provider&#39; =&gt; &#39;users&#39;,<br>    ],</pre><pre>    &#39;api&#39; =&gt; [<br>        &#39;driver&#39; =&gt; &#39;passport&#39;,<br>        &#39;provider&#39; =&gt; &#39;users&#39;,<br>    ],<br>],</pre><p>1–8. 创建UserTableSeeder，并且导入测试数据</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1250045829d8d0a1373e8598d3bf30b6/href">https://medium.com/media/1250045829d8d0a1373e8598d3bf30b6/href</a></iframe><pre>composer dump-autoload</pre><pre>php artisan db:seed --class=UsersTableSeeder</pre><p>1–9. 测试获取Token。记的把以下代码中的域名换成自己的测试环境域名，secret换成1–4里面 client_id=2 对应的 secret。<br>测试工具按自己习惯，此处使用curl。</p><pre>curl — request POST \<br> — url <strong>http://multiauth.test</strong>/oauth/token \<br> — header ‘accept: application/json’ \<br> — header ‘content-type: application/x-www-form-urlencoded’ \<br> — data ‘username=usera%40gmail.com&amp;password=userasecret&amp;client_id=2&amp;client_secret=<strong>secret</strong>&amp;grant_type=password&amp;scope=’</pre><p>1–10. 如果以上的每一步操作都没错的话，应该可以看见以下的输出了</p><pre>{“token_type”:”Bearer”,”expires_in”:31536000,”access_token”:”eyJ0e...&quot;,”refresh_token”:”def50...”}</pre><p>下一章：<a href="https://medium.com/@zxishere/%E5%9F%BA%E4%BA%8Elaravel-passport-api-%E7%9A%84%E5%A4%9A%E7%94%A8%E6%88%B7%E5%A4%9A%E5%AD%97%E6%AE%B5%E8%AE%A4%E8%AF%81%E7%B3%BB%E7%BB%9F-%E4%BA%8C-9c12cfb9edd4">基于Laravel Passport API 的多用户多字段认证系统（二）：多用户登录</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f98881d20092" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>