<article><h1>Laravel 的用戶認證系統</h1><ul><li><a href="#introduction">簡介</a><ul><li><a href="#introduction-database-considerations">數據庫注意事項</a></li></ul></li><li><a href="#authentication-quickstart">認證快速入門</a><ul><li><a href="#included-routing">路由</a></li><li><a href="#included-views">視圖</a></li><li><a href="#included-authenticating">認證</a></li><li><a href="#retrieving-the-authenticated-user">獲取已認證的用戶信息</a></li><li><a href="#protecting-routes">限制路由訪問</a></li><li><a href="#login-throttling">登入限流</a></li></ul></li><li><a href="#authenticating-users">手動認證用戶</a><ul><li><a href="#remembering-users">記住用戶</a></li><li><a href="#other-authentication-methods">其它認證方法</a></li></ul></li><li><a href="#http-basic-authentication">HTTP 基礎認證</a><ul><li><a href="#stateless-http-basic-authentication">無狀態 HTTP 基礎認證</a></li></ul></li><li><a href="https://github.com/laravel/socialite">社交認證</a></li><li><a href="#adding-custom-guards">增加自定義 Guard</a></li><li><a href="#adding-custom-user-providers">增加自定義用戶 Provider</a><ul><li><a href="#the-user-provider-contract">用戶 Provider Contract</a></li><li><a href="#the-authenticatable-contract">用戶認證 Contract</a></li></ul></li><li><a href="#events">事件</a></li></ul><p><a name="introduction"></a></p><h2><a href="#introduction">簡介</a></h2><blockquote class="has-icon tip"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="56.6px" height="87.5px" viewBox="0 0 56.6 87.5" enable-background="new 0 0 56.6 87.5" xml:space="preserve"><path fill="#FFFFFF" d="M28.7 64.5c-1.4 0-2.5-1.1-2.5-2.5v-5.7 -5V41c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5v10.1 5 5.8C31.2 63.4 30.1 64.5 28.7 64.5zM26.4 0.1C11.9 1 0.3 13.1 0 27.7c-0.1 7.9 3 15.2 8.2 20.4 0.5 0.5 0.8 1 1 1.7l3.1 13.1c0.3 1.1 1.3 1.9 2.4 1.9 0.3 0 0.7-0.1 1.1-0.2 1.1-0.5 1.6-1.8 1.4-3l-2-8.4 -0.4-1.8c-0.7-2.9-2-5.7-4-8 -1-1.2-2-2.5-2.7-3.9C5.8 35.3 4.7 30.3 5.4 25 6.7 14.5 15.2 6.3 25.6 5.1c13.9-1.5 25.8 9.4 25.8 23 0 4.1-1.1 7.9-2.9 11.2 -0.8 1.4-1.7 2.7-2.7 3.9 -2 2.3-3.3 5-4 8L41.4 53l-2 8.4c-0.3 1.2 0.3 2.5 1.4 3 0.3 0.2 0.7 0.2 1.1 0.2 1.1 0 2.2-0.8 2.4-1.9l3.1-13.1c0.2-0.6 0.5-1.2 1-1.7 5-5.1 8.2-12.1 8.2-19.8C56.4 12 42.8-1 26.4 0.1zM43.7 69.6c0 0.5-0.1 0.9-0.3 1.3 -0.4 0.8-0.7 1.6-0.9 2.5 -0.7 3-2 8.6-2 8.6 -1.3 3.2-4.4 5.5-7.9 5.5h-4.1H28h-0.5 -3.6c-3.5 0-6.7-2.4-7.9-5.7l-0.1-0.4 -1.8-7.8c-0.4-1.1-0.8-2.1-1.2-3.1 -0.1-0.3-0.2-0.5-0.2-0.9 0.1-1.3 1.3-2.1 2.6-2.1H41C42.4 67.5 43.6 68.2 43.7 69.6zM37.7 72.5H26.9c-4.2 0-7.2 3.9-6.3 7.9 0.6 1.3 1.8 2.1 3.2 2.1h4.1 0.5 0.5 3.6c1.4 0 2.7-0.8 3.2-2.1L37.7 72.5z"></path></svg></span></div> <strong>想要快速起步?</strong> 在一個全新的 Laravel 應用中運行 <code class=" language-php">php artisan make<span class="token punctuation">:</span>auth</code> 和 <code class=" language-php">php artisan migrate</code> 命令,然后可以用瀏覽器訪問 <code class=" language-php">http<span class="token punctuation">:</span><span class="token operator">/</span><span class="token operator">/</span>your<span class="token operator">-</span>app<span class="token punctuation">.</span>dev<span class="token operator">/</span>register</code> 或者你在程序中定義的其他 url。這個兩個簡單的命令就可以搭建好整個認證系統的腳手架。</p></blockquote><p>Laravel 中實現用戶認證非常簡單。實際上,幾乎所有東西都已經為你配置好了。配置文件位于 <code class=" language-php">config<span class="token operator">/</span>auth<span class="token punctuation">.</span>php</code>,其中包含了用于調整認證服務行為的、標注好注釋的選項配置。</p><p>在其核心代碼中,Laravel 的認證組件由 <code class=" language-php">guards</code> 和 <code class=" language-php">providers</code> 組成,Guard 定義了用戶在每個請求中如何實現認證,例如,Laravel 通過 <code class=" language-php">session</code> guard 來維護 Session 存儲的狀態和 Cookie。</p><p>Provider 定義了如何從持久化存儲中獲取用戶信息,Laravel 底層支持通過 Eloquent 和數據庫查詢構建器兩種方式來獲取用戶,如果需要的話,你還可以定義額外的 Provider。</p><p>如果看到這些名詞覺得很困惑,大可不必太過擔心,因為對絕大多數應用而言,只需使用默認認證配置即可,不需要做什么改動。</p><p><a name="introduction-database-considerations"></a></p><h3>數據庫注意事項</h3><p>默認的 Laravel 在 <code class=" language-php">app</code> 文件夾中會含有 <code class=" language-php">App\<span class="token package">User</span></code> <a href="/docs/5.4/eloquent">Eloquent 模型</a>。這個模型將使用默認的 Eloquent 認證來驅動。如果你的應用程序沒有使用 Eloquent,請選擇使用 Laravel 查詢構造器的 <code class=" language-php">database</code> 認證驅動。</p><p>為 <code class=" language-php">App\<span class="token package">User</span></code> 模型創建數據庫表結構時,確認密碼字段最少必須 60 字符長。保持字段原定的 255 字符長是個好選擇。</p><p><code class=" language-php">users</code> 數據表中必須含有 nullable 、100 字符長的 <code class=" language-php">remember_token</code> 字段。當用戶登錄應用并勾選「記住我」時,這個字段將會被用來保存「記住我」 session 的令牌。</p><p><a name="authentication-quickstart"></a></p><h2><a href="#authentication-quickstart">認證快速入門</a></h2><p>Laravel 帶有幾個預設的認證控制器,它們被放置在 <code class=" language-php">App\<span class="token package">Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Auth</span></code> 命名空間內,<code class=" language-php">RegisterController</code> 處理用戶注冊,<code class=" language-php">LoginController</code> 處理用戶認證,<code class=" language-php">ForgotPasswordController</code> 處理重置密碼的 e-mail 鏈接,<code class=" language-php">ResetPasswordController</code> 包含重置密碼的邏輯。 這些控制器使用了 trait 來包含所需要的方法,對于大多數的應用程序而言,你并不需要修改這些控制器。</p><p><a name="included-routing"></a></p><h3>路由</h3><p>Laravel 通過運行如下命令可快速生成認證所需要的路由和視圖:</p><pre class=" language-php"><code class=" language-php">php artisan make<span class="token punctuation">:</span>auth</code></pre><p>該命令應該在新安裝的應用下使用,它會生成 layout 布局視圖,注冊和登錄視圖,以及所有的認證路由,同時生成 <code class=" language-php">HomeController</code> ,用來處理登錄成功后會跳轉到該控制器下的請求。</p><p><a name="included-views"></a></p><h3>視圖</h3><p>正如上面所提到的,<code class=" language-php">php artisan make<span class="token punctuation">:</span>auth</code> 命令會在 <code class=" language-php">resources<span class="token operator">/</span>views<span class="token operator">/</span>auth</code> 目錄下創建所有認證需要的視圖。</p><p><code class=" language-php">make<span class="token punctuation">:</span>auth</code> 命令還創建了 <code class=" language-php">resources<span class="token operator">/</span>views<span class="token operator">/</span>layouts</code> 目錄,該目錄下包含了應用的基礎布局文件。所有這些視圖都基于 Bootstrap CSS 框架,你也可以根據需要對其進行自定義。</p><p><a name="included-authenticating"></a></p><h3>認證</h3><p>現在你已經為自帶的認證控制器設置好了路由和視圖,接下來我們來實現新用戶注冊和登錄認證。你可以在瀏覽器中訪問定義好的路由,認證控制器已經(通過 trait)包含了注冊及登錄邏輯。</p><h4>自定義路徑</h4><p>當一個用戶成功進行登錄認證后,默認將會跳轉到 <code class=" language-php"><span class="token operator">/</span>home</code>,你可以通過在 <code class=" language-php">LoginController</code>,<code class=" language-php">RegisterController</code> 和 <code class=" language-php">ResetPasswordController</code> 中設置 <code class=" language-php">redirectTo</code> 屬性來自定義登錄認證成功之后的跳轉路徑:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">protected</span> <span class="token variable">$redirectTo</span> <span class="token operator">=</span> <span class="token string">'/'</span><span class="token punctuation">;</span></code></pre><p>如果跳轉路徑需要自定義邏輯來生成,你可以定義 <code class=" language-php">redirectTo</code> 方法來代替 <code class=" language-php">redirectTo</code> 屬性:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function">redirectTo<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string">'/path'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><blockquote class="has-icon tip"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="56.6px" height="87.5px" viewBox="0 0 56.6 87.5" enable-background="new 0 0 56.6 87.5" xml:space="preserve"><path fill="#FFFFFF" d="M28.7 64.5c-1.4 0-2.5-1.1-2.5-2.5v-5.7 -5V41c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5v10.1 5 5.8C31.2 63.4 30.1 64.5 28.7 64.5zM26.4 0.1C11.9 1 0.3 13.1 0 27.7c-0.1 7.9 3 15.2 8.2 20.4 0.5 0.5 0.8 1 1 1.7l3.1 13.1c0.3 1.1 1.3 1.9 2.4 1.9 0.3 0 0.7-0.1 1.1-0.2 1.1-0.5 1.6-1.8 1.4-3l-2-8.4 -0.4-1.8c-0.7-2.9-2-5.7-4-8 -1-1.2-2-2.5-2.7-3.9C5.8 35.3 4.7 30.3 5.4 25 6.7 14.5 15.2 6.3 25.6 5.1c13.9-1.5 25.8 9.4 25.8 23 0 4.1-1.1 7.9-2.9 11.2 -0.8 1.4-1.7 2.7-2.7 3.9 -2 2.3-3.3 5-4 8L41.4 53l-2 8.4c-0.3 1.2 0.3 2.5 1.4 3 0.3 0.2 0.7 0.2 1.1 0.2 1.1 0 2.2-0.8 2.4-1.9l3.1-13.1c0.2-0.6 0.5-1.2 1-1.7 5-5.1 8.2-12.1 8.2-19.8C56.4 12 42.8-1 26.4 0.1zM43.7 69.6c0 0.5-0.1 0.9-0.3 1.3 -0.4 0.8-0.7 1.6-0.9 2.5 -0.7 3-2 8.6-2 8.6 -1.3 3.2-4.4 5.5-7.9 5.5h-4.1H28h-0.5 -3.6c-3.5 0-6.7-2.4-7.9-5.7l-0.1-0.4 -1.8-7.8c-0.4-1.1-0.8-2.1-1.2-3.1 -0.1-0.3-0.2-0.5-0.2-0.9 0.1-1.3 1.3-2.1 2.6-2.1H41C42.4 67.5 43.6 68.2 43.7 69.6zM37.7 72.5H26.9c-4.2 0-7.2 3.9-6.3 7.9 0.6 1.3 1.8 2.1 3.2 2.1h4.1 0.5 0.5 3.6c1.4 0 2.7-0.8 3.2-2.1L37.7 72.5z"></path></svg></span></div> <code class=" language-php">redirectTo</code> 方法優先于 <code class=" language-php">redirectTo</code> 屬性。</p></blockquote><h4>自定義用戶名</h4><p>Laravel默認使用 <code class=" language-php">email</code> 字段來認證。如果你想用其他字段認證,可以在 <code class=" language-php">LoginController</code> 里面定義一個 <code class=" language-php">username</code> 方法</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">username<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string">'username'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><h4>自定義 Guard</h4><p>你還可以自定義實現用戶認證的 「guard」,要實現這一功能,需要在 <code class=" language-php">LoginController</code>,<code class=" language-php">RegisterController</code> 和 <code class=" language-php">ResetPasswordController</code> 中定義 <code class=" language-php">guard</code> 方法,該方法需要返回一個 guard 實例:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span>
<span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function">guard<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">guard<span class="token punctuation">(</span></span><span class="token string">'guard-name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><h4>自定義驗證 / 存儲</h4><p>要修改新用戶注冊所必需的表單字段,或者自定義新用戶字段如何存儲到數據庫,你可以修改 <code class=" language-php">RegisterController</code> 類。該類負責為應用驗證輸入參數和創建新用戶。</p><p><code class=" language-php">RegisterController</code> 的 <code class=" language-php">validator</code> 方法包含了新用戶的驗證規則,你可以按需要自定義該方法。</p><p><code class=" language-php">RegisterController</code> 的 <code class=" language-php">create</code> 方法負責使用 <a href="/docs/5.4/eloquent">Eloquent ORM</a> 在數據庫中創建新的 <code class=" language-php">App\<span class="token package">User</span></code> 記錄。當然,你也可以基于自己的需求自定義該方法。</p><p><a name="retrieving-the-authenticated-user"></a></p><h3>獲取已認證的用戶信息</h3><p>可以通過 <code class=" language-php">Auth</code> facade 來訪問認證的用戶。</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">
// 獲取當前已通過認證的用戶...
</span><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">user<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">
// 獲取當前已通過認證的用戶id...
</span><span class="token variable">$id</span> <span class="token operator">=</span> <span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">id<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>也有另外一種方法可以訪問認證過的用戶,就是通過 <code class=" language-php">Illuminate\<span class="token package">Http<span class="token punctuation">\</span>Request</span></code> 實例,請注意類型提示的類會被自動注入:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">ProfileController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* Update the user's profile.
*
* @param Request $request
* @return Response
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">update<span class="token punctuation">(</span></span>Request <span class="token variable">$request</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // $request->user() 返回認證過的用戶的實例...
</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><h4>檢查用戶是否登錄</h4><p>使用 <code class=" language-php">Auth</code> facade 的 <code class=" language-php">check</code> 方法來檢查用戶是否登錄,如果已經登錄,將會返回 <code class=" language-php"><span class="token boolean">true</span></code>:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">check<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // 這個用戶已經登錄...
</span><span class="token punctuation">}</span></code></pre><blockquote class="has-icon tip"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="56.6px" height="87.5px" viewBox="0 0 56.6 87.5" enable-background="new 0 0 56.6 87.5" xml:space="preserve"><path fill="#FFFFFF" d="M28.7 64.5c-1.4 0-2.5-1.1-2.5-2.5v-5.7 -5V41c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5v10.1 5 5.8C31.2 63.4 30.1 64.5 28.7 64.5zM26.4 0.1C11.9 1 0.3 13.1 0 27.7c-0.1 7.9 3 15.2 8.2 20.4 0.5 0.5 0.8 1 1 1.7l3.1 13.1c0.3 1.1 1.3 1.9 2.4 1.9 0.3 0 0.7-0.1 1.1-0.2 1.1-0.5 1.6-1.8 1.4-3l-2-8.4 -0.4-1.8c-0.7-2.9-2-5.7-4-8 -1-1.2-2-2.5-2.7-3.9C5.8 35.3 4.7 30.3 5.4 25 6.7 14.5 15.2 6.3 25.6 5.1c13.9-1.5 25.8 9.4 25.8 23 0 4.1-1.1 7.9-2.9 11.2 -0.8 1.4-1.7 2.7-2.7 3.9 -2 2.3-3.3 5-4 8L41.4 53l-2 8.4c-0.3 1.2 0.3 2.5 1.4 3 0.3 0.2 0.7 0.2 1.1 0.2 1.1 0 2.2-0.8 2.4-1.9l3.1-13.1c0.2-0.6 0.5-1.2 1-1.7 5-5.1 8.2-12.1 8.2-19.8C56.4 12 42.8-1 26.4 0.1zM43.7 69.6c0 0.5-0.1 0.9-0.3 1.3 -0.4 0.8-0.7 1.6-0.9 2.5 -0.7 3-2 8.6-2 8.6 -1.3 3.2-4.4 5.5-7.9 5.5h-4.1H28h-0.5 -3.6c-3.5 0-6.7-2.4-7.9-5.7l-0.1-0.4 -1.8-7.8c-0.4-1.1-0.8-2.1-1.2-3.1 -0.1-0.3-0.2-0.5-0.2-0.9 0.1-1.3 1.3-2.1 2.6-2.1H41C42.4 67.5 43.6 68.2 43.7 69.6zM37.7 72.5H26.9c-4.2 0-7.2 3.9-6.3 7.9 0.6 1.3 1.8 2.1 3.2 2.1h4.1 0.5 0.5 3.6c1.4 0 2.7-0.8 3.2-2.1L37.7 72.5z"></path></svg></span></div> 盡管可以使用 <code class=" language-php">check</code> 方法來檢查用戶是否登錄,在允許該用戶訪問特定的路由或控制器之前,可以使用中間件來檢查用戶是否認證過。要想得到更多信息,請閱讀 <a href="/docs/5.4/authentication#protecting-routes">限制路由訪問</a> 的文檔。</p></blockquote><p><a name="protecting-routes"></a></p><h3>限制路由訪問</h3><p><a href="/docs/5.4/middleware">路由中間件</a> 用于限定認證過的用戶訪問指定的路由,Laravel 提供了 <code class=" language-php">auth</code> 中間件來達到這個目的,而這個中間件被定義在 <code class=" language-php">app\<span class="token package">Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>Authenticate</span><span class="token punctuation">.</span>php</code> 中。因為這個中間件已經在 HTTP kernel 中注冊了,只需要將它應用到路由定義中即可使用:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get<span class="token punctuation">(</span></span><span class="token string">'profile'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // 只有認證過的用戶能進來這里...
</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token string">'auth'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>如果使用 <a href="/docs/5.4/controllers">控制器類</a>,可以在構造器中調用 <code class=" language-php">middleware</code> 方法,來代替在路由中直接定義:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token string">'auth'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><h4>指定一個Guard</h4><p>添加 <code class=" language-php">auth</code> 中間件到路由后,還需要指定使用哪個 guard 來實現認證。指定的 guard 對應配置文件 <code class=" language-php">auth<span class="token punctuation">.</span>php</code> 中 <code class=" language-php">guards</code> 數組的某個鍵:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token string">'auth:api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><p><a name="login-throttling"></a></p><h3>登錄限流</h3><p>Laravel 內置的 <code class=" language-php">LoginController</code> 類提供 <code class=" language-php">Illuminate\<span class="token package">Foundation<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>ThrottlesLogins</span></code> trait 允許你在應用程序中限制登錄次數。默認情況下,如果用戶在進行幾次嘗試后仍不能提供正確的憑證,將在一分鐘內無法進行登錄。這個限制會特別針對用戶的用戶名稱 / 郵件地址和他們的 IP 地址。</p><p><a name="authenticating-users"></a></p><h2><a href="#authenticating-users">手動認證用戶</a></h2><p>當然,不一定要使用 Laravel 內置的認證控制器。如果選擇刪除這些控制器,可以直接調用 Laravel 的認證類來實現用戶認證管理。不用擔心,很簡單。</p><p>我們可以利用 <code class=" language-php">Auth</code> <a href="/docs/5.4/facades">facade</a> 來訪問 Laravel 的認證服務,因此需要確認在類的頂部導入 <code class=" language-php">Auth</code> facade。接下來讓我們看一下 <code class=" language-php">Auth</code> 的 <code class=" language-php">attempt</code> 方法:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">LoginController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* Handle an authentication attempt.
*
* @return Response
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">authenticate<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">attempt<span class="token punctuation">(</span></span><span class="token punctuation">[</span><span class="token string">'email'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token variable">$email</span><span class="token punctuation">,</span> <span class="token string">'password'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token variable">$password</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // Authentication passed...
</span> <span class="token keyword">return</span> <span class="token function">redirect<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">intended<span class="token punctuation">(</span></span><span class="token string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p><code class=" language-php">attempt</code> 方法會接受一個數組來作為第一個參數,這個數組的值可用來尋找數據庫里的用戶數據,所以在上面的例子中,用戶通過 <code class=" language-php">email</code> 字段被取出,如果用戶被找到了,數據庫里經過哈希的密碼將會與數組中哈希的 <code class=" language-php">password</code> 值比對,如果兩個值一樣的話就會開啟一個通過認證的 session 給用戶。</p><p>如果認證成功,<code class=" language-php">attempt</code> 方法將會返回 <code class=" language-php"><span class="token boolean">true</span></code>,反之則為 <code class=" language-php"><span class="token boolean">false</span></code>。</p><p>重定向器上的 <code class=" language-php">intended</code> 方法將會重定向用戶回原本想要進入的頁面,也可以傳入一個回退 URI 至這個方法,以避免要轉回的頁面不可使用。</p><h4>指定額外條件</h4><p>可以加入除用戶的郵箱及密碼外的額外條件進行認證查找。例如,我們要確認用戶是否被標示為 <code class=" language-php">active</code>:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">attempt<span class="token punctuation">(</span></span><span class="token punctuation">[</span><span class="token string">'email'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token variable">$email</span><span class="token punctuation">,</span> <span class="token string">'password'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token variable">$password</span><span class="token punctuation">,</span> <span class="token string">'active'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // The user is active, not suspended, and exists.
</span><span class="token punctuation">}</span></code></pre><blockquote class="has-icon note"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="90px" height="90px" viewBox="0 0 90 90" enable-background="new 0 0 90 90" xml:space="preserve"><path fill="#FFFFFF" d="M45 0C20.1 0 0 20.1 0 45s20.1 45 45 45 45-20.1 45-45S69.9 0 45 0zM45 74.5c-3.6 0-6.5-2.9-6.5-6.5s2.9-6.5 6.5-6.5 6.5 2.9 6.5 6.5S48.6 74.5 45 74.5zM52.1 23.9l-2.5 29.6c0 2.5-2.1 4.6-4.6 4.6 -2.5 0-4.6-2.1-4.6-4.6l-2.5-29.6c-0.1-0.4-0.1-0.7-0.1-1.1 0-4 3.2-7.2 7.2-7.2 4 0 7.2 3.2 7.2 7.2C52.2 23.1 52.2 23.5 52.1 23.9z"></path></svg></span></div> 在這些例子中,<code class=" language-php">email</code> 不是一個一定要有的選項,它僅僅是被用來當作例子,你可以用任何字段,只要它在數據庫的意義等同于「用戶名」。</p></blockquote><h4>訪問指定 Guard 實例</h4><p>可以通過 <code class=" language-php">Auth</code> facade 的 <code class=" language-php">guard</code> 方法來指定使用特定的 guard 實例。這樣可以實現在應用不同部分管理用戶認證時使用完全不同的認證模型或者用戶表。</p><p>傳遞給 <code class=" language-php">guard</code> 方法 guard 名稱必須是 <code class=" language-php">auth<span class="token punctuation">.</span>php</code> 配置文件中 guards 的值之一:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">guard<span class="token punctuation">(</span></span><span class="token string">'admin'</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">attempt<span class="token punctuation">(</span></span><span class="token variable">$credentials</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span><span class="token punctuation">}</span></code></pre><h4>注銷用戶</h4><p>要想讓用戶注銷,你可以使用 <code class=" language-php">Auth</code> facade 的 <code class=" language-php">logout</code> 方法。這個方法會清除所有認證后加入到用戶 session 的數據:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">logout<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p><a name="remembering-users"></a></p><h2><a href="#remembering-users">記住用戶</a></h2><p>如果你想要提供「記住我」的功能,你需要傳入一個布爾值到 <code class=" language-php">attempt</code> 方法的第二個參數,在用戶注銷前 session 值都會被一直保存。<code class=" language-php">users</code> 數據表一定要包含一個 <code class=" language-php">remember_token</code> 字段,這是用來保存「記住我」令牌的。</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">attempt<span class="token punctuation">(</span></span><span class="token punctuation">[</span><span class="token string">'email'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token variable">$email</span><span class="token punctuation">,</span> <span class="token string">'password'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token variable">$password</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token variable">$remember</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // 這個用戶被記住了...
</span><span class="token punctuation">}</span></code></pre><blockquote class="has-icon tip"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="56.6px" height="87.5px" viewBox="0 0 56.6 87.5" enable-background="new 0 0 56.6 87.5" xml:space="preserve"><path fill="#FFFFFF" d="M28.7 64.5c-1.4 0-2.5-1.1-2.5-2.5v-5.7 -5V41c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5v10.1 5 5.8C31.2 63.4 30.1 64.5 28.7 64.5zM26.4 0.1C11.9 1 0.3 13.1 0 27.7c-0.1 7.9 3 15.2 8.2 20.4 0.5 0.5 0.8 1 1 1.7l3.1 13.1c0.3 1.1 1.3 1.9 2.4 1.9 0.3 0 0.7-0.1 1.1-0.2 1.1-0.5 1.6-1.8 1.4-3l-2-8.4 -0.4-1.8c-0.7-2.9-2-5.7-4-8 -1-1.2-2-2.5-2.7-3.9C5.8 35.3 4.7 30.3 5.4 25 6.7 14.5 15.2 6.3 25.6 5.1c13.9-1.5 25.8 9.4 25.8 23 0 4.1-1.1 7.9-2.9 11.2 -0.8 1.4-1.7 2.7-2.7 3.9 -2 2.3-3.3 5-4 8L41.4 53l-2 8.4c-0.3 1.2 0.3 2.5 1.4 3 0.3 0.2 0.7 0.2 1.1 0.2 1.1 0 2.2-0.8 2.4-1.9l3.1-13.1c0.2-0.6 0.5-1.2 1-1.7 5-5.1 8.2-12.1 8.2-19.8C56.4 12 42.8-1 26.4 0.1zM43.7 69.6c0 0.5-0.1 0.9-0.3 1.3 -0.4 0.8-0.7 1.6-0.9 2.5 -0.7 3-2 8.6-2 8.6 -1.3 3.2-4.4 5.5-7.9 5.5h-4.1H28h-0.5 -3.6c-3.5 0-6.7-2.4-7.9-5.7l-0.1-0.4 -1.8-7.8c-0.4-1.1-0.8-2.1-1.2-3.1 -0.1-0.3-0.2-0.5-0.2-0.9 0.1-1.3 1.3-2.1 2.6-2.1H41C42.4 67.5 43.6 68.2 43.7 69.6zM37.7 72.5H26.9c-4.2 0-7.2 3.9-6.3 7.9 0.6 1.3 1.8 2.1 3.2 2.1h4.1 0.5 0.5 3.6c1.4 0 2.7-0.8 3.2-2.1L37.7 72.5z"></path></svg></span></div> 如果使用 Laravel 內置的 <code class=" language-php">LoginController</code>,合適的「記住我」邏輯已經通過 traits 實現。</p></blockquote><p>可以使用 <code class=" language-php">viaRemember</code> 方法來檢查這個用戶是否使用「記住我」 cookie 來做認證:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">viaRemember<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span><span class="token punctuation">}</span></code></pre><p><a name="other-authentication-methods"></a></p><h3>其它認證方法</h3><h4>用「用戶實例」做認證</h4><p>如果你需要使用存在的用戶實例來登錄,你需要調用 <code class=" language-php">login</code> 方法,并傳入使用實例,這個對象必須是由 <code class=" language-php">Illuminate\<span class="token package">Contracts<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Authenticatable</span></code> <a href="/docs/5.4/contracts">contract</a> 所實現。當然,<code class=" language-php">App<span class="token operator">/</span>User</code> 模型已經實現了這個接口:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">login<span class="token punctuation">(</span></span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">
// 登錄并且「記住」用戶
</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">login<span class="token punctuation">(</span></span><span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>你也可以指定 guard 實例:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">guard<span class="token punctuation">(</span></span><span class="token string">'admin'</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">login<span class="token punctuation">(</span></span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h4>通過用戶 ID 做認證</h4><p>使用 <code class=" language-php">loginUsingId</code> 方法來登錄指定 ID 用戶,這個方法接受要登錄用戶的主鍵:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">loginUsingId<span class="token punctuation">(</span></span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">
// 登錄并且「記住」用戶
</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">loginUsingId<span class="token punctuation">(</span></span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h4>僅在本次認證用戶</h4><p>可以使用 <code class=" language-php">once</code> 方法來針對一次性認證用戶,沒有任何的 session 或 cookie 會被使用,這個對于構建無狀態的 API 非常的有用,<code class=" language-php">once</code> 方法跟 <code class=" language-php">attempt</code> 方法擁有同樣的傳入參數:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">once<span class="token punctuation">(</span></span><span class="token variable">$credentials</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span><span class="token punctuation">}</span></code></pre><p><a name="http-basic-authentication"></a></p><h2><a href="#http-basic-authentication">HTTP 基礎認證</a></h2><p><a href="http://en.wikipedia.org/wiki/Basic_access_authentication">HTTP 基礎認證</a> 提供一個快速的方法來認證用戶,不需要任何「登錄」頁面。開始之前,先增加 <code class=" language-php">auth<span class="token punctuation">.</span>basic</code> <a href="/docs/5.4/middleware">中間件</a> 到你的路由,<code class=" language-php">auth<span class="token punctuation">.</span>basic</code> 中間件已經被包含在 Laravel 框架中,所以你不需要定義它:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get<span class="token punctuation">(</span></span><span class="token string">'profile'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // 只有認證過的用戶可進入...
</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token string">'auth.basic'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>一旦中間件被增加到路由上,當使用瀏覽器進入這個路由時,將自動的被提示需要提供憑證。默認情況下,<code class=" language-php">auth<span class="token punctuation">.</span>basic</code> 中間件將會使用用戶的 <code class=" language-php">email</code> 字段當作「用戶名」。</p><h4>FastCGI 的注意事項</h4><p>如果是正在使用 FastCGI,則 HTTP 的基礎認證可能無法正常運作,你需要將下面這幾行加入你 <code class=" language-php"><span class="token punctuation">.</span>htaccess</code> 文件中:</p><pre class=" language-php"><code class=" language-php">RewriteCond <span class="token operator">%</span><span class="token punctuation">{</span><span class="token constant">HTTP</span><span class="token punctuation">:</span>Authorization<span class="token punctuation">}</span> <span class="token operator">^</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token operator">+</span><span class="token punctuation">)</span>$
RewriteRule <span class="token punctuation">.</span><span class="token operator">*</span> <span class="token operator">-</span> <span class="token punctuation">[</span>E<span class="token operator">=</span><span class="token constant">HTTP_AUTHORIZATION</span><span class="token punctuation">:</span><span class="token operator">%</span><span class="token punctuation">{</span><span class="token constant">HTTP</span><span class="token punctuation">:</span>Authorization<span class="token punctuation">}</span><span class="token punctuation">]</span></code></pre><p><a name="stateless-http-basic-authentication"></a></p><h3>無狀態 HTTP 基礎認證</h3><p>你可以使用 HTTP 基礎認證而不用在 session 中設置用戶認證用的 cookie,這個功能對 API 認證來說非常有用。為了達到這個目的,<a href="/docs/5.4/middleware">定義一個中間件</a> 并調用 <code class=" language-php">onceBasic</code> 方法。如果從 <code class=" language-php">onceBasic</code> 方法沒有返回任何響應的話,這個請求會直接傳進應用程序中:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Middleware</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">AuthenticateOnceWithBasicAuth</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">handle<span class="token punctuation">(</span></span><span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$next</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">onceBasic<span class="token punctuation">(</span></span><span class="token punctuation">)</span> <span class="token operator">?</span><span class="token punctuation">:</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p>接著,<a href="/docs/5.4/middleware#registering-middleware">注冊這個路由中間件</a>,然后將它增加在一個路由上:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get<span class="token punctuation">(</span></span><span class="token string">'api/user'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // 只有認證過的用戶可以進入...
</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token string">'auth.basic.once'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p><a name="adding-custom-guards"></a></p><h2><a href="#adding-custom-guards">增加自定義的 Guard</a></h2><p>你可以使用 <code class=" language-php">Auth</code> 的 <code class=" language-php">extend</code> 方法來自定義認證 Guard,你需要在 <a href="/docs/5.4/providers">服務提供者</a> 中放置此代碼調用。因為 Laravel 已經提供 <code class=" language-php">AuthServiceProvider</code>,可以把代碼放入其中:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Services<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>JwtGuard</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Providers<span class="token punctuation">\</span>AuthServiceProvider</span> <span class="token keyword">as</span> ServiceProvider<span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">AuthServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* Register any application authentication / authorization services.
*
* @return void
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">boot<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">registerPolicies<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">extend<span class="token punctuation">(</span></span><span class="token string">'jwt'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$app</span><span class="token punctuation">,</span> <span class="token variable">$name</span><span class="token punctuation">,</span> <span class="token keyword">array</span> <span class="token variable">$config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // Return an instance of Illuminate\Contracts\Auth\Guard...
</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">JwtGuard</span><span class="token punctuation">(</span><span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">createUserProvider<span class="token punctuation">(</span></span><span class="token variable">$config</span><span class="token punctuation">[</span><span class="token string">'provider'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p>正如上面的代碼所示,<code class=" language-php">extend</code> 方法傳參進去的回調需要返回 <code class=" language-php">Illuminate\<span class="token package">Contracts<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Guard</span></code> 的實現,這個接口類有幾個方法你需要實現。定制好 Guard 以后,你需要在配置信息中開啟使用:</p><pre class=" language-php"><code class=" language-php"><span class="token string">'guards'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'api'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'driver'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token string">'jwt'</span><span class="token punctuation">,</span>
<span class="token string">'provider'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token string">'users'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre><p><a name="adding-custom-user-providers"></a></p><h2><a href="#adding-custom-user-providers">添加自定義用戶提供者</a></h2><p>如果你沒有使用傳統的關系型數據庫存儲用戶信息,則需要使用自己的認證用戶提供者來擴展 Laravel。我們使用 <code class=" language-php">Auth</code> facade 上的 <code class=" language-php">provider</code> 方法定義自定義該提供者:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Extensions<span class="token punctuation">\</span>RiakUserProvider</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">AuthServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* Register any application authentication / authorization services.
*
* @return void
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">boot<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">registerPolicies<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Auth<span class="token punctuation">::</span></span><span class="token function">provider<span class="token punctuation">(</span></span><span class="token string">'riak'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$app</span><span class="token punctuation">,</span> <span class="token keyword">array</span> <span class="token variable">$config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // Return an instance of Illuminate\Contracts\Auth\UserProvider...
</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">RiakUserProvider</span><span class="token punctuation">(</span><span class="token variable">$app</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">make<span class="token punctuation">(</span></span><span class="token string">'riak.connection'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p>通過 <code class=" language-php">provider</code> 方法注冊用戶提供者后,你可以在配置文件 <code class=" language-php">config<span class="token operator">/</span>auth<span class="token punctuation">.</span>php</code> 中切換到新的用戶提供者。首先,在該配置文件定義一個使用新驅動的 <code class=" language-php">providers</code> 數組:</p><pre class=" language-php"><code class=" language-php"><span class="token string">'providers'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'users'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'driver'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token string">'riak'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre><p>然后,可以在你的 <code class=" language-php">guards</code> 配置中使用這個提供者:</p><pre class=" language-php"><code class=" language-php"><span class="token string">'guards'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'web'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'driver'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token string">'session'</span><span class="token punctuation">,</span>
<span class="token string">'provider'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token string">'users'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre><p><a name="the-user-provider-contract"></a></p><h3>UserProvider 契約</h3><p><code class=" language-php">Illuminate\<span class="token package">Contracts<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>UserProvider</span></code> 的實現只負責獲取 <code class=" language-php">Illuminate\<span class="token package">Contracts<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Authenticatable</span></code> 的實現, 且不受限于永久保存系統,例如 MySQL, Riak 等等。這兩個接口允許 Laravel 認證機制繼續作用,而不用管用戶如何保存或是使用什么樣類型的類實現它。</p><p>讓我們來看看 <code class=" language-php">Illuminate\<span class="token package">Contracts<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>UserProvider</span></code> contract:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span>
<span class="token keyword">interface</span> <span class="token class-name">UserProvider</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">retrieveById<span class="token punctuation">(</span></span><span class="token variable">$identifier</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">retrieveByToken<span class="token punctuation">(</span></span><span class="token variable">$identifier</span><span class="token punctuation">,</span> <span class="token variable">$token</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">updateRememberToken<span class="token punctuation">(</span></span>Authenticatable <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token variable">$token</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">retrieveByCredentials<span class="token punctuation">(</span></span><span class="token keyword">array</span> <span class="token variable">$credentials</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">validateCredentials<span class="token punctuation">(</span></span>Authenticatable <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token keyword">array</span> <span class="token variable">$credentials</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><p><code class=" language-php">retrieveById</code> 函數通常獲取一個代表用戶的值,例如 MySQL 中自增的 ID。<code class=" language-php">Authenticatable</code> 的實現通過 ID 匹配的方法來取出和返回。</p><p><code class=" language-php">retrieveByToken</code> 函數借助用戶唯一的 <code class=" language-php"><span class="token variable">$identifier</span></code> 和「記住我」<code class=" language-php"><span class="token variable">$token</span></code> 來獲取用戶。如同之前的方法,<code class=" language-php">Authenticatable</code> 的實現應該被返回。</p><p><code class=" language-php">updateRememberToken</code> 方法使用新的 <code class=" language-php"><span class="token variable">$token</span></code> 更新了 <code class=" language-php"><span class="token variable">$user</span></code> 的 <code class=" language-php">remember_token</code> 字段。這個新的令牌可以是全新的令牌(當使用「記住我」嘗試登錄成功時),或是 null(當用戶注銷時)。</p><p><code class=" language-php">retrieveByCredentials</code> 方法獲取了從 <code class=" language-php"><span class="token scope">Auth<span class="token punctuation">::</span></span>attempt</code> 方法發送過來的憑證數組(當想要登錄時)。這個方法應該要 「查找」所使用的持久化存儲系統來匹配這些憑證。通常,這個方法會運行一個帶著「where」<code class=" language-php"><span class="token variable">$credentials</span><span class="token punctuation">[</span><span class="token string">'username'</span><span class="token punctuation">]</span></code> 條件的查找。這個方法接著需要返回一個 <code class=" language-php">UserInterface</code> 的實現。<strong>此方法不應該企圖做任何密碼驗證或認證操作。</strong></p><p><code class=" language-php">validateCredentials</code> 方法需要比較 <code class=" language-php"><span class="token variable">$user</span></code> 和 <code class=" language-php"><span class="token variable">$credentials</span></code> 來認證這個用戶。例如,這個方法可能會使用 <code class=" language-php"><span class="token scope">Hash<span class="token punctuation">::</span></span>check</code> 比較 <code class=" language-php"><span class="token variable">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">getAuthPassword<span class="token punctuation">(</span></span><span class="token punctuation">)</span></code> 字符串及 <code class=" language-php"><span class="token variable">$credentials</span><span class="token punctuation">[</span><span class="token string">'password'</span><span class="token punctuation">]</span></code>。這個方法通過返回一個布爾值來驗證密碼是否正確。</p><p><a name="the-authenticatable-contract"></a></p><h3>用戶認證 Contract</h3><p>現在我們已經介紹了 <code class=" language-php">UserProvider</code> 的每個方法,讓我們看一下 <code class=" language-php">Authenticate</code> contract。這個提供者需要 <code class=" language-php">retrieveById</code> 和 <code class=" language-php">retrieveByCredentials</code> 方法來返回這個接口的實現:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span>
<span class="token keyword">interface</span> <span class="token class-name">Authenticatable</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getAuthIdentifierName<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getAuthIdentifier<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getAuthPassword<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getRememberToken<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">setRememberToken<span class="token punctuation">(</span></span><span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getRememberTokenName<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><p>這個接口很簡單。<code class=" language-php">getAuthIdentifierName</code> 方法需要返回「主鍵名字」。<code class=" language-php">getAuthIdentifier</code> 方法需要返回用戶的「主鍵」。在 MySQL 中,這個主鍵是指自動增加的主鍵。而 <code class=" language-php">getAuthPassword</code> 應該要返回用戶哈希后的密碼。這個接口允許認證系統和任何用戶類運作,不用管你在使用何種 ORM 或存儲抽象層。默認情況下,Laravel 的 <code class=" language-php">app</code> 文件夾中會包含 <code class=" language-php">User</code> 類來實現此接口,所以你可以觀察這個類以作為實現的例子。</p><p><a name="events"></a></p><h2><a href="#events">事件</a></h2><p>Laravel 提供了在認證過程中的各種 <a href="/docs/5.4/events">事件</a>。你可以在 <code class=" language-php">EventServiceProvider</code> 中對這些事件做監聽:</p><pre class=" language-php"><code class=" language-php"><span class="token comment" spellcheck="true">/**
* 為應用程序的事件監聽器的映射
*
* @var array
*/</span>
<span class="token keyword">protected</span> <span class="token variable">$listen</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token string">'Illuminate\Auth\Events\Registered'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'App\Listeners\LogRegisteredUser'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">'Illuminate\Auth\Events\Attempting'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'App\Listeners\LogAuthenticationAttempt'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">'Illuminate\Auth\Events\Authenticated'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'App\Listeners\LogAuthenticated'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">'Illuminate\Auth\Events\Login'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'App\Listeners\LogSuccessfulLogin'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">'Illuminate\Auth\Events\Failed'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'App\Listeners\LogFailedLogin'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">'Illuminate\Auth\Events\Logout'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'App\Listeners\LogSuccessfulLogout'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">'Illuminate\Auth\Events\Lockout'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'App\Listeners\LogLockout'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></article>
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- 請求周期
- 開發環境部署
- Valet
- Homestead
- 核心概念
- 服務提供者
- Facades
- Contracts
- 服務容器
- HTTP 層
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- Session
- 表單驗證
- 前端
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全
- API 認證
- 用戶認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- Redis
- 數據填充
- Eloquent ORM
- Eloquent ORM快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- 序列化
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 錯誤與日志
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度