やりたいこと
Laravel Breezeの初期設定だとアカウント新規登録時にメールアドレスの確認をしない。
リンク付きメールでアドレスの確認をしてもらいたい。
smtpサーバーの準備
.envにメールの設定を書いておく。
https://qiita.com/tiro_sx/items/b4cb9a44ebc62821c6f7
userコントローラー編集
app/Controllers/user.php
+ use Illuminate\Contracts\Auth\MustVerifyEmail;
- class User extends Authenticatable
+ class User extends Authenticatable implements MustVerifyEmail
{
authをverifiedに変える
routes/web.php
middleware('auth')-> //メール認証前でも通す
middleware('verified')-> //メール認証前は通さない
これだけでregister時にリンク付きメールでアドレスの確認をしてくれます。
何でもやってくれてありがたい。
問題
プロフィールページでメールアドレスを変更する処理が不親切。
(メールアドレスを変更してから認証メールが送られる。
打ち間違えとかあるから、認証してからメールアドレスを変更したい。)
う~ん。
簡単にやる方法が見つからないから泥臭くやります。
■userテーブルに新メールアドレスとトークンを持たせる。
database/migrations/
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('new_email_token')->after('email')->nullable()->comment('メアド変更用');
$table->string('new_email')->after('email')->nullable()->comment('メアド変更用');
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('new_email_token');
$table->dropColumn('new_email');
});
}
};
■プロフィールコントローラーを変える。
app/Contorollers/ProfileController.php
public function update(ProfileUpdateRequest $request): RedirectResponse
{
$oldMail = auth()->user()->email??null;
$newMail = $request->email??null;
$request->user()->fill($request->validated());
if ($request->user()->isDirty('email')) {
$token = generateRandomString(10);
$request->user()->email = $oldMail;
$request->user()->new_email = $newMail;
$request->user()->new_email_token = $token;
$url = route('profile.mailUpdate', [auth()->user()->id, $token]);
$text = "
以下のURLにアクセスしてメールアドレスの変更を完了させてください。
・該当アカウントにログイン中のブラウザでアクセスする必要があります。
・有効期限は1時間です。
$url
当メールに心当たりのない場合はこのメールを破棄してください。
";
Mail::raw($text, function ($message) use ($newMail){
$message->to($newMail)->subject('メールアドレスの変更');
});
$send = 1;
}
$request->user()->save();
return Redirect::route('profile.edit')->with('status', 'profile-updated')->with('send', $send??null);;
}
// ユーザーのメールアドレスを更新する
public function mailUpdate(Request $request, $id, $token)
{
$usr = auth()->user();
$duplicateCheck = user::where('email', $usr->new_email)->first();
$timeLimitCheck = ($usr->updated_at->diffInHours(now()) < 1);
//メールアドレス変更
if($usr->id == $id
&& $usr->new_email_token == $token
&& $usr->new_email
&& $usr->new_email_token
&& !$duplicateCheck
&& $timeLimitCheck
){
$usr->email = $usr->new_email;
$usr->new_email = null;
$usr->new_email_token = null;
$usr->save();
$mailStatus = 'メールアドレスを変更しました。';
//変更せず
}else{
$mailStatus = 'メールアドレスを変更できませんでした。';
}
return Redirect::route('mypage')->with('mailStatus', $mailStatus);
}
//ランダムな英数字を出力
if (!function_exists('generateRandomString')) {
function generateRandomString($length = 5) {
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, strlen($characters) - 1)];
}
return $randomString;
}
}
■メッセージ
blade側
@if(session('mailStatus'))
{{session('mailStatus')}}
@endif
//..
@if (session('send'))
<p>※新しいメールアドレスに送られたURLをクリックして変更を完了させてください。</p>
@endif
■ルーティング
route
Route::middleware(['auth:sanctum', 'verified'])
->get('/mypage/profile/mailupdate/{id}/{token}', [ProfileController::class, 'mailUpdate'])
->name('profile.mailUpdate');
もっとシンプルにできる方法がありましたら更新します。