虽然Laravel框架中默认自带了邮箱认证的功能,可以很方便地进行集成,但我还是想搞清楚其流程,所以今天花了一上午的时间进行理解。
首先,先定义邮箱认证的业务流程。
基本业务流程如下:
- 用户注册成功后,系统会自动发送一个附带“认证链接”邮件到用户邮箱;
- 用户打开“认证链接”即为激活账号,才可以正常访问系统;
- 用户在未通过邮箱进行验证的情况下,所有访问都会重定向到邮箱验证页面。
然后,再看邮箱认证的代码实现。
代码实现流程如下:
1.通过use Trait将Laravel自带的邮箱认证功能集成User模型中。这个Trait中包含邮箱认证的相关方法,包括user表中相关字段判断用户Email是否已认证、将其设置为已认证等。
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Auth\MustVerifyEmail as MustVerifyEmailTrait;
//Contract契约,实现这个接口,继承此类将确保User遵守契约,拥有上面提到的四个方法
class User extends Authenticatable implements MustVerifyEmailContract
{
//加载使用“MustVerifyEmail”Trait,这个Trait中包含邮箱认证的相关方法,包括user表中相关字段判断用户Email是否已认证、将其设置为已认证等
use Notifiable, MustVerifyEmailTrait;
......
}
2、分析laravel自带的RegisterController控制器,主要是用作邮箱认证的业务处理。其中使用了laravel的事件系统通过event(new Registered())触发Registered事件,然后使用listener对这个事件进行监听(所谓的监听就是将事件类与监听类之间建立关联)。
在RegisterController中引入了“RegistersUsers” Trait
use RegistersUsers;
在加载的Illuminate\Foundation\Auth\RegistersUsers Trait中register()方法对用户提交表单后的逻辑进行了处理。
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());
}
其中最关键的一点是使用了Laravel的事件系统,触发Registered事件。
注:laravel的事件系统就是一个简单的观察者模式,能够订阅和监听应用中发生的各种事件。事件系统有利用应用各个方面的解耦,因为单个事件可以拥有多个互不依赖的监听器。对于设计模式其实我也有点绕,后面再慢慢研究吧。
在app/Providers/EventServiceProvider.php
文件的$listen属性中可以看到注册了Registered事件的监听器。
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];
在SendEmailVerificationNotification类里对事件进行了处理,满足一定条件的话就发送认证邮件。
class SendEmailVerificationNotification
{
//处理事件
public function handle(Registered $event)
{
// 如果 user 是继承于 MustVerifyEmail 并且还未激活的话
if ($event->user instanceof MustVerifyEmail && ! $event->user->hasVerifiedEmail()) {
// 发送邮件认证消息通知(认证邮件)
$event->user->sendEmailVerificationNotification();
}
}
}
3、通过Laravel中间件来过滤用户的所有请求,强制未注册用户进行认证,否则的话不能正常访问除认证页面外的其他页面。
创建一个中间件Middleware,对请求进行过滤,如果请求用户未认证的话,就跳转到邮件认证提醒的页面中。
public function handle($request, Closure $next)
{
// 三个判断:
// 1. 如果用户已经登录
// 2. 并且还未认证 Email
// 3. 并且访问的不是 email 验证相关 URL 或者退出的 URL。
if ($request->user() &&
! $request->user()->hasVerifiedEmail() &&
! $request->is('email/*', 'logout')) {
// 根据客户端返回对应的内容
return $request->expectsJson()
? abort(403, 'Your email address is not verified.')
: redirect()->route('verification.notice');
}
return $next($request);
}
中间件创建完成之后,需要在app/Http/Kernel.php中注册,这里要注意注册注册时机必须在StartSession后面,因为StartSession是启动会话,$request->user()的判断必须在会话已启动的情况下,否则永远都是false。
class Kernel extends HttpKernel
{
.
.
.
protected $middlewareGroups = [
'web' => [
...
\Illuminate\Session\Middleware\StartSession::class,
...
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\EnsureEmailIsVerified::class, // 邮箱认证中间件
],
];
.
.
.
}
大概流程就是以上三步,虽然内容不多,但还是需要好好理解理解。