laravel 项目实现邮箱验证功能

邮箱验证功能在很多网站都有用到,我的个人网站上也用到,邮箱验证需要用到邮件发送服务,Laravel 提供了非常简单的邮件发送 API,Laravel 项目实现邮件发送功能很简单,下面我开始介绍一下我的具体实现。

邮箱验证

邮箱验证功能实现具体步骤如下:

  1. 添加字段,为用户表添加两个字段,验证令牌 (verification_token) 和验证状态 (verified) 。
  2. 生成令牌。
  3. 用户登录后,检测是否验证过邮箱,没有则引导去验证。
  4. 使用阿里云企业邮箱发送邮箱验证链接。
  5. 用户点击邮箱验证链接完成验证。

添加字段

使用命令生成迁移文件,命令如下:

$ 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_USERNAMEMAIL_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,全栈开发工程师和终身学习者。
不喜勿喷,以人为善,比聪明更重要。
欢迎留言和关注,且接受任何宝贵的建议。
了解更多

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容