邮箱验证功能在很多网站都有用到,我的个人网站上也用到,邮箱验证需要用到邮件发送服务,Laravel 提供了非常简单的邮件发送 API,Laravel 项目实现邮件发送功能很简单,下面我开始介绍一下我的具体实现。
邮箱验证
邮箱验证功能实现具体步骤如下:
- 添加字段,为用户表添加两个字段,验证令牌 (
verification_token
) 和验证状态 (verified
) 。 - 生成令牌。
- 用户登录后,检测是否验证过邮箱,没有则引导去验证。
- 使用阿里云企业邮箱发送邮箱验证链接。
- 用户点击邮箱验证链接完成验证。
添加字段
使用命令生成迁移文件,命令如下:
$ php artisan make:migration add_verification_to_users_table --table=users
命令会在 database/migrations
目录下生成迁移文件 [timestamp]\_add\_verification\_to\_users\_table.php
,修改迁移文件,修改后如下:
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddVerificationToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('verification_token')->nullable();
$table->boolean('verified')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('verification_token');
$table->dropColumn('verified');
});
}
接着我运行迁移,将字段加入到用户表中。运行命令如下:
php artisan migrate
生成令牌
我希望用户注册的时候就给用户生成令牌,所以我在 App
目录下创建 Observers
目录,并在 Observers
目录下创建 UserObserver.php
文件,并编写如下代码:
namespace App\Observers;
use App\Models\Article;
use App\Models\Comment;
use App\Models\Reply;
use App\Models\User;
class UserObserver
{
public function creating(User $user)
{
$user->verification_token=str_random(30);
}
}
在 app/Providers
目录下的 AppServiceProvider.php
文件中 注册监听 Eloquent
事件,代码如下:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
\App\Models\User::observe(\App\Observers\UserObserver::class);
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}
用户登录后,检测是否验证过邮箱,没有则引导去验证
用户登录后,会检测邮箱是否验证,如果没有验证就会出现邮箱未验证的提示,并引导用户去验证。效果图如下:
实现引导的代码如下:
@if(Auth::check() && !Auth::user()->verified&&!Request::is('email_verification_required'))
<article class="message is-warning">
<div class="message-body">
邮箱未激活,请前往 {{ Auth::user()->email }} 查收激活邮件,激活后才能完整地使用社区功能,如发帖和回帖。未收到邮件?请前往 <a class="has-text-danger" href="{{ route('email-verification-required') }}">重发邮件</a> 。
</div>
</article>
@endif
设置路由,修改 routes
目录下 web.php
文件,增加一个路由,代码如下:
Route::get('/email_verification_required', 'UsersController@emailVerificationRequired')->name('email-verification-required');
接下来为用户控制器定义一个 emailVerificationRequired
方法,该方法将用于用户点击引导链接进入邮件发送页面,页面效果如下:
emailVerificationRequired
方法具体实现代码如下:
app/Http/Controllers/UsersController.php
public function emailVerificationRequired(){
return view('users.edit_email_notify');
}
实现页面代码如下:
resources/views/users/edit_email_notify.blade.php
@extends('layouts.app')
@section('title', '发送邮箱验证')
@section('content')
<section class="section">
<div class="container">
<div class="columns">
<div class="column is-offset-4 is-4">
<div class="card">
<div class="card-content ">
<h2><i class="fa fa-cog" aria-hidden="true"></i> 验证邮箱</h2>
<hr>
<article class="message is-warning">
<div class="message-body">
<p>邮箱未激活,请前往 {{ Auth::user()->email }} 查收激活邮件,激活后才能完整地使用网站功能,如评论、订阅专栏。</p>
<br>
<p> 未收到邮件?请点击以下按钮重新发送验证邮件。</p>
</div>
</article>
<form class="form-horizontal" method="POST" action="{{ route('users.send-verification-mail')}}" accept-charset="UTF-8">
{!! csrf_field() !!}
<div class="">
<button class="button is-link is-fullwidth"><i class="fa fa-paper-plane" aria-hidden="true"></i> 重新发送验证邮件</button>
</div>
<br>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
@stop
使用阿里云企业邮箱发送邮箱验证链接。
接下来我们要开始使用邮箱发送功能,在 Laravel 中,可以通过 Mail
接口的 send
方法来进行邮件发送,示例如下:
$view = 'emails.email_verification';
$data = compact('user');
$from = 'aufree@yousails.com';
$name = 'Aufree';
$to = $user->email;
$subject = "感谢注册 Sample 应用!请确认你的邮箱。";
Mail::send($view, $data, function ($message) use ($from, $name, $to, $subject) {
$message->from($from, $name)->to($to)->subject($subject);
});
Laravel 中邮箱发送的配置存放于 config/mail.php
中。不过 mail.php
中我们所需的配置,都可以通过 .env
来配置。作为最佳实践,我们优先选择通过环境变量来配置:
.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mxhichina.com
MAIL_PORT=25
MAIL_USERNAME=xxxxxxxxxxxxxx@sevdot.com
MAIL_PASSWORD=xxxxxxxxx
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=xxxxxxxxxxxxxx@sevdot.com
MAIL_FROM_NAME=SevDot
选项 MAIL_USERNAME
和 MAIL_FROM_ADDRESS
需保存一致,为邮箱账号,MAIL_PASSWORD
为邮箱的登录密码。
设置路由,修改 routes
目录下 web.php
文件,增加一个路由,代码如下:
Route::post('/users/send_verification_mail', 'UsersController@sendVerificationMail')->name('users.send-verification-mail');
接下来为用户控制器定义一个 sendVerificationMail
方法,该方法将用于发送邮件给指定用户。具体代码实现如下:
app/Http/Controllers/UsersController.php
public function sendVerificationMail(){
$user= Auth::user();
$this->sendEmailConfirmationTo($user);
session()->flash('success', '验证邮件已发送到您的注册邮箱上,请注意查收。');
return redirect('/');
}
protected function sendEmailConfirmationTo($user)
{
$view = 'emails.email_verification';
$data = compact('user');
$to = $user->email;
$subject = "感谢注册 SevDot,请验证邮箱";
Mail::send($view, $data, function ($message) use ($to, $subject) {
$message->to($to)->subject($subject);
});
}
在 Laravel 中,我们使用视图来构建邮件模板,在用户查收邮件时,该模板将作为内容展示视图。接下来我们需要创建一个用于渲染注册邮件的 email_verification
视图。
resources/views/emails/email_verification.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>注册确认链接</title>
</head>
<body>
<h1>感谢您在 SevDot 网站进行注册!</h1>
<p>
请点击下面的链接完成注册:
<a href="{{ route('verified_email',$user->verification_token) }}">
{{ route('verified_email', $user->verification_token) }}
</a>
</p>
<p>
如果这不是您本人的操作,请忽略此邮件。
</p>
</body>
</html>
到此邮件发送功能已经实现,用户点击发送验证邮箱按钮,就会收到邮件,用户可以进入邮箱,点击邮件链接验证邮箱。
用户点击邮箱验证链接完成验证。
上面我们已经成功发送邮件,用户会收到邮件,用户点击进行验证邮箱,我们继续完成验证邮箱功能。
设置路由,修改 routes
目录下 web.php
文件,增加一个路由,代码如下:
routes/web.php
Route::get('/email_verification/{token}', 'UsersController@verifiedEmail')->name('verified_email');
接下来为用户控制器定义一个 verifiedEmail
方法,该方法将用于验证邮箱。具体代码实现如下:
app/Http/Controllers/UsersController.php
public function verifiedEmail($token){
$user = User::where('verification_token',$token)->first();
$user->verified = true;
$user->verification_token = null;
$user->save();
Auth::login($user);
session()->flash('success', '恭喜您,邮箱验证成功!');
return redirect('/');
}
至此邮箱验证功能已经全部完成,但是可能会出现一些问题。
FQA
1. 本地开发完成,本地可以正常发送邮件,但是上传至阿里云服务器以后不能发送邮件
原因是阿里云禁用了 25 端口,解决方案是改 .env
文件,将 MAIL_PORT=25
改为 MAIL_PORT=465
,将 MAIL_ENCRYPTION=tls
改为 MAIL_ENCRYPTION=ssl
。
感谢阅读,我是sevdot,全栈开发工程师和终身学习者。
不喜勿喷,以人为善,比聪明更重要。
欢迎留言和关注,且接受任何宝贵的建议。
了解更多