Edited at

Laravelでユーザーのメールアドレスを変更するフロー

More than 3 years have passed since last update.


環境

Laravel 5.1


経緯

現在PHP+Laravelなシステムを開発していますが、ユーザーが設定画面などでメールアドレスを変更したいと思った時に、メールアドレスの打ち間違いなどを考慮してどのようなフローでやるのが正解かなと色々参考にした結果、まあまあ満足できる出来になったので共有します。ちなみに訳あってデフォルトのUserモデルを使用していませんが、適宜直せば大丈夫だと思います。

参考

LARAVEL 5.1 のユーザー登録で確認メールを送る【前篇】


フローの説明

ざっくり説明すると、


  1. ユーザーが新しいメールアドレスを入力して送信ボタンを押す。

  2. 新しいメールアドレスを元にユニークなトークンをデータベースに保存して、そのトークンを含めた承認URLを新しいメールアドレスあてに送信する。

  3. ユーザーがメールを開いて書かれてあるURLをクリックする。

  4. トークンがデータベースにあるかどうか確認して、あればユーザーのメールアドレスを更新する。なければエラー画面を出す。

  5. トークンを削除する。

こんな感じです。では以下で実装例を紹介します。


コントローラの実装

ユーザーが新しいメールアドレスを入力して送信ボタンを押したところから説明を始めます。


SettingsController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Session;
use Mail;
use DB;
use App\User;

class SettingsController extends Controller
{
public function changeMail(Request $request)
{
// ログインしているユーザーを取ってくる
$user = User::find(Session::get('id'));

$address = $request->input('newAddress');
$token = hash_hmac(
'sha256',
str_random(40).$address,
env('APP_KEY')
);
$domain = env('APP_DOMAIN');

Mail::send(
'emails.authorize',
['url' => "https:{$domain}/settings/authorizeMail/?token={$token}"],
function ($message) use ($address, $domain) {
$message->from(env('MAIL_ADDRESS'));
$message->sender(env('MAIL_ADDRESS'));
$message->to($address);
$message->subject('メールアドレス変更確認');
}
);

DB::table('email_changes')->insert([
[
'id' => $user->id,
'email' => $address,
'token' => $token
]
]);

return view('sendMailCompleted');
}

public function authorizeMail(Request $request)
{
$token = $request->input('token');

$email_changes = DB::table('email_changes')
->where('token', '=', $token)
->first();

$user = User::find($email_changes->id);
$user->email = $email_changes->email;
$user->save();

DB::table('email_changes')
->where('token', '=', $token)
->delete();

return view('authorizeMailCompleted');
}
}



実装説明

email_changesというテーブルにトークンとユーザーのIDと新しいメールアドレスを格納しておきます。そして、承認画面(ここでは/settings/authorizeMail)のMiddlewareでバリデーションしないようにしないといけません。あとはコード量も多くないので読んで分かると思います。

bladeテンプレートとかは各自で好きなように作ってください。あとは全くコントローラ内でバリデーションをかけていないので、参考にする際はトークンがリクエストに入っていない場合などを考慮して実装してください。