laravel邮箱认证

继上文laravel用户认证,本篇将实现新用户需要邮箱验证才能注册成功

邮箱认证流程

分为两步:

  • 发送认证邮件 —— 将附带认证信息的『认证链接』发送到用户邮箱里;
  • 检测认证链接 —— 用户打开邮件,点击认证链接进入网站,程序检测 URL 中认证参数的合法性,并渲染对应的页面。

代码实现

routes/web.php 的认证路由改为:

代码语言:javascript
复制
Auth::routes(['verify' => true]);

app/User.php 引入 MustVerifyEmailTrait 即可完成邮箱验证

代码语言:javascript
复制
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Auth\MustVerifyEmail as MustVerifyEmailTrait;
use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmailContract
{
    use Notifiable, MustVerifyEmailTrait;
protected $fillable = [
    'name', 'email', 'password',
];

protected $hidden = [
    'password', 'remember_token',
];

protected $casts = [
    'email_verified_at' => 'datetime',
];

}

代码解析

分析laravel自带的app/Http/Controllers/Auth/RegisterController.php,注册调用的是:RegistersUsers这个trait的register方法:

vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers.php

代码语言:javascript
复制
public function register(Request $request)
{
this->validator(request->all())->validate();

event(new Registered($user = $this->create($request->all())));

$this->guard()->login($user);

return $this->registered($request, $user)
                ?: redirect($this->redirectPath());

}

使用 event(new Registered(user = this->create(request-&gt;all())));</code> laravel的事件系统,表示触发了<code>Registered</code>事件,打开 <code>app/Providers/EventServiceProvider.php</code> 文件,此文件的 listen 属性里我们可以看到注册了 Registered 事件的监听器:

代码语言:javascript
复制
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];

打开 vendor/laravel/framework/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php, 查看具体的监听器代码:

代码语言:javascript
复制
public function handle(Registered $event)
{
if (event-&gt;user instanceof MustVerifyEmail &amp;&amp; ! event->user->hasVerifiedEmail()) {
$event->user->sendEmailVerificationNotification();
}
}

因此只需要满足event-&gt;user instanceof MustVerifyEmail &amp;&amp; ! event->user->hasVerifiedEmail()即可实现邮件认证功能

测试认证

开发环境中,可以将邮件内容写到日志中,便于调试。将 .envMAIL_DRIVER 设置为:

代码语言:javascript
复制
MAIL_DRIVER=log

然后新注册一个用户,提交表单后,查看storage/logs/laravel-2019-03-25.log目录下最新的日志文件,能看到laravel发送的验证内容

image

中间件验证权限

新注册的用户并没有进行邮箱验证,可以通过 dd(\Auth::user()->hasVerifiedEmail()); 测试是否已经验证

我们要实现的逻辑是:未验证的用户自动跳转到邮箱验证提示页面。可以借助中间件来实现此功能

代码语言:javascript
复制
 php artisan make:middleware EnsureEmailIsVerified</code></pre></div></div><p>自动创建 <code>app/Http/Middleware/EnsureEmailIsVerified.php</code></p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">public function handle(request, Closure $next)
{
// 判断用户是否需要邮箱验证
// 1. 用户已登录
// 2. 未认证Email
// 3. 访问的不是email验证相关url或者退出的url
if (request-&gt;user() &amp;&amp; !request->user()->hasVerifiedEmail() && !$request->is('email/*', 'logout')) {
return $request->expectsJson() ? abort(403, '您的邮箱尚未验证') : redirect()->route('verification.notice');
}
return next(request);
}

此时,我们再访问 http://www.test.com/home ,代码经由中间件时,符合邮箱验证条件,因此会被自动跳转到 http://www.test.com/email/verify

image

我们将log文件中的验证链接粘贴到浏览器访问,即可成功验证

小结

邮件认证的功能,laravel已经帮我们封装好了,只需进行简单的调用。难点在于理顺整个逻辑