邮箱验证与激活,可以说是现在web app里的必备功能了,在laravel 5.7以前的版本,你得自行实现这个功能,从5.7开始,开箱即有此功能了。这里我们就演示一下,如何在用户注册了以后,自动发送一个激活邮件到其邮箱,然后用户在点击了激活链接以后,才能激活账户,才能进一步访问受限的页面。

(一)数据库层面的设计原理

首先,在一个全新的laravel 5.7项目里,当你配置好.env里的数据库等以后,执行

php artisan migrate

然后呢,我们查看数据库中users表的结构,以更好地理解其背后原理:

file

可以看到,相较于以前的版本,表里多了一个email_verified_at这么一栏,用来记录用户激活账户的时间。当用户注册了以后,点击了邮箱里的链接,这一栏就会记录激活的时间,这样我们就能基于这一栏是否存在时间信息来确定用户激活了没有。通常呢,我们可能会设置一个类似verified_or_not的一栏,然后将其设置为boolean属性,1就是激活了的正式用户,0就代表还没激活的非正式用户。那么这里laravel用的是时间的类型,既可以达到传统上的是非判断目的,同时还保存了激活的时间信息,这样后期比如我们想着知道这个用户成为正式会员多久了,或者其他任何的时间信息处理,就更灵活和易于扩展了。

(二)开启auth,查看相应视图

php artisan make:auth

执行了这个以后,除了往常的以外,还会新增一个verify.blade.php,这个是当开启了邮箱验证功能,用户注册了以后的提示页面,前台显示效果如下:

file

(三)在user model中实现相应的interface

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements MustVerifyEmail
{
    use Notifiable;
	  ...	
}

默认的User Model里会多了一个use Illuminate\Contracts\Auth\MustVerifyEmail;,这是一个Contracts,也可以说是一个Interface,那么我们需要做的,只是加上implements MustVerifyEmail这点即可。

(四)添加邮箱验证的路由

routes\web.php中,当执行了make:auth以后,默认会多了下面这个路由:

Auth::routes();

那么要让邮箱验证生效,我们还要将其改成:

Auth::routes(['verify' => true]);

加了这个以后,VerificationController.php里的相应逻辑就会生效。

(五)使用verified中间件保护相应的页面

假设我们想着/home页面,只有在用户激活了邮件以后才能真的访问,否则的话就一直提示他需要激活邮件,那么很简单,加上新增的verified中间件即可。我们在HomeController里就可以这样:

public function __construct()
    {
        $this->middleware(['auth', 'verified']);
    }

(六)配置好相应的邮件服务

既然是得发邮件,必须得配置好相应的邮件服务,这个我们课程里都有了,在这儿就不多提了,这里我还是用mailtrap测试:

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

(七)实际测试效果

这个时候,你注册一个用户,应该就会有下面的页面提示:

file

然后到你相应的邮箱里,应该就会多了一个激活邮件,大致如下:

file

那么这个时候,如果你不点击激活链接,就无法访问/home的正常内容,如果点击了链接,就能正常访问了。

同时,当你点击了链接以后,再去数据库看,就会发现email_verified_at一栏多了相应的时间信息:

file

(八)这样就完事了吗?

这样就完事了吗?其实不然.

这个新功能解决了如何在用户注册了以后就给他发送一封邮件,而且是激活邮件,但是邮件发送这种高能耗的服务,通常是不能直接就执行的,如果一个新用户点了注册以后,发现你的网站得转老半天才出现发送了注册邮件的提示消息,那么就难免给这个用户不好的第一印象,让他觉得你这个网站或应用是不是整体上都很慢呢?第一印象不好,是很糟糕的.尤其是现在的用户,普遍会在注册环节有着急或急躁的心理状态,因为大部分时候,用户要注册你的网站或应用,是因为他想尝试或使用你的某项服务,但是点击了以后,你的应用却让其注册,没办法,他不得不注册,与此同时也就不自觉着急了,想着赶紧注册完然后好体验实际的内容或服务,这样的心态下,如果注册环节稍微复杂些,或者期间出了别的差错,那么用户会毫不留情地离开.除非你所提供的服务,是他无法在市面上找到替代产品的,但即使那样,糟糕的注册流程体验,也会招致新用户的心里埋怨.所以了,在注册环节,因为发送邮件多转几圈而让用户产生误解,是完全没必要的,也是必须要避免的.

当然了,任何时候都不要让用户一直等着邮件发送这个缓慢的动作,而laravel 5.7的这个新的功能,是没有涉及这一点的,这自然是怕整的过于高深复杂,影响了新手的体验和尝试.但是不论是出于学习,还是实际使用,我们总要不断追求最优实践,不是吗?

那么如何延迟邮件发送呢?也即如何将一些高能耗的操作,放到队列中去执行,从而提高用户体验呢?

进一步地,如何使用自定义的队列job或通道呢?虽然我们说要延迟发送邮件,但是如果延迟了老半天,也没有发过去,害得用户一个劲儿地去刷新邮箱,那这个用户你也基本就流失掉了.这就需要你在延迟邮件的时候,考虑到队列的优先级问题,让注册邮件的发送有一个相对高的优先级,或者有一个专门的处理通道,这样就不会说假设你后台有一个媒体转码的队列,它触发得早,需要执行一两天,然后就阻塞了你的邮件队列,导致你一两天才发送出去注册邮件,这肯定是不行的.

再比如,如何使用内容队列方面最专业的beanstalk服务来处理队列?或者redis也行.如何将队列操作与事件操作结合起来?因为实际当中,一个用户注册的时候,往往要操作很多事项,不只是一个注册邮件这么简单,那么怎么综合运用事件\队列\邮件\消息等等的底层服务,将这一流程处理得相对完美呢?

也即往深了去看,一个看似简单的邮件操作,都要涉及到不少的laravel底层应用,而底层的这些应用,往往是牵一发动全身——可能你单独地看event、cache、session、queue、mailer这些文档,你都懂,都挺简单的,但是你一旦要用到其中的某一个,就必然会涉及到其他的那些,单独地会其中的一个在实际当中往往没用,你更需要的是这些底层的服务结合在一起一般怎么用,而这也就是我们《Laravel底层实战兼核心源码解析》这一课程的魅力所在——通过精心编排的课程设计,让你在不知不觉中对这些“错综复杂”的底层应用游刃有余 。

比如,上面提到的高级邮件实践,在我们课程的《邮件发送也可以有大文章》这一章,就带领大家以发送注册邮件的实例,一步步地体验了mailer、eloquent observer、system events、custom events、queue job、beanstalk等各种底层的综合应用,只是一章就让你对这些“拦路虎”不再迷茫畏惧,而且这一章实际内容还不止这些~

当然,这还是只是一章的“精彩”而已,更多数不尽的“精彩”,我们一起课程中见吧~