💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
<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">&lt;?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-&gt;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">&gt;</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">&gt;</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">&gt;</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">&lt;?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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&lt;?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">&gt;</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">&lt;?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">&gt;</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">&gt;</span> <span class="token punctuation">[</span> <span class="token string">'api'</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token punctuation">[</span> <span class="token string">'driver'</span> <span class="token operator">=</span><span class="token operator">&gt;</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">&gt;</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">&lt;?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">&gt;</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">&gt;</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">&gt;</span> <span class="token punctuation">[</span> <span class="token string">'users'</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token punctuation">[</span> <span class="token string">'driver'</span> <span class="token operator">=</span><span class="token operator">&gt;</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">&gt;</span> <span class="token punctuation">[</span> <span class="token string">'web'</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token punctuation">[</span> <span class="token string">'driver'</span> <span class="token operator">=</span><span class="token operator">&gt;</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">&gt;</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">&lt;?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">&gt;</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">&lt;?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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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">&gt;</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>