Laravel5.5を使用してメール認証を使った会員登録を実装した時に、こちらの記事を参考にましたが、メール認証と仮会員登録を別々のtableで管理したかったのでその時の備忘録もかねて紹介したいと思います。
##前提
- 参考記事で一通りのユーザー登録画面が作成してある
##流れ
1.仮会員のメールアドレスを登録
2.登録したアドレスにメールを送る
3.メールにあるURLをクリック
4.本会員登録用の入力フォームを登録する
5.本会員登録完了
###メール認証用のtableを作成する
今回はemail_verifications
という名前で、メール認証用のテーブルを作成します。
php artisan make:migration create_email_verification_table
作成したmigrationファイルにメール認証に必要なカラムを記載していきます。
- email:メールアドレス
- token:メールアドレス確認用のトークン
- status:仮会員登録のステータス
- expiration_datetime:有効期限
を追加したいと思います。
class CreateEmailVerification extends Migration
{
public function up()
{
Schema::create('email_verifications', function (Blueprint $table) {
$table->increments('id');
$table->string('email', 255)->comment('メールアドレス');
$table->string('token', 250)->comment('確認トークン');
$table->tinyInteger('status')->comment('ステータス');
$table->dateTime('expiration_datetime')->comment('有効期限');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('email_verifications');
}
}
###仮会員のメールアドレス登録画面を作る
仮会員登録時は「メールアドレス」だけ登録してもらうようにします。
register.blade.phpを編集して「メールアドレス」以外の項目を削除します。
###仮会員登録処理を実装する
routeをweb.php
に追加します。
Route::post('/register', 'Auth\RegisterController@emailVerification');
routeの設定に間違いがあったので訂正しましたmm
####Mode\EmailVerificationを作成する
email_verifications
に登録するModelを作成します。
php artisan make:model EmailVerification
class EmailVerification extends Model
{
const SEND_MAIL = 0; // 仮会員登録のメール送信
const MAIL_VERIFY = 1; //メールアドレス認証
const REGISTER = 2; // 本会員登録完了
protected $fillable = [
'email',
'token',
'status',
'expiration_datetime',
];
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
}
public static function build($email, $hours = 1)
{
$emailVerification = new self([
'email' => $email,
'token' => str_random(250),
'status' => self::SEND_MAIL,
'expiration_datetime' => Carbon::now()->addHours($hours),
]);
return $emailVerification;
}
}
status
は仮会員ということで「0」を登録しておきます。
expiration_datetime
は仮会員の有効期限なので1時間くらいに設定しておきます。
####RegisterControllerの更新
validator()の更新
メールアドレスのチェックだけなのでemail_validator()
を作成しました。
protected function email_validator(array $data)
{
return Validator::make($data, [
'email' => 'required|string|email||unique:users,email',
]);
}
今回は、Users
テーブルとは別テーブルに仮会員登録をしたいのですが、メールアドレスは重複させたくなかったので、email_validator()
にはunique:user,email
を追加しました。
これで本登録した時に、Users
テーブルで重複したメールアドレスが無くせるかと思います。
emailVerification()を追記
仮会員用のメールアドレスを、作成した新しいテーブルemail_verifications
に登録する処理を追記します。
public function emailVerification(Request $request)
{
$validator = $this->email_validator($request->all());
if ($validator->fails()) {
return view('auth.register')
->with([
'email' => $request->email,
])
->withErrors($validator);
} else {
$emailVerification = EmailVerification::build($request->email);
DB::beginTransaction();
try {
$emailVerification->saveOrFail();
DB::commit();
} catch (\Throwable $e) {
DB::rollBack();
Log::warning("メールアドレス変更処理に失敗しました。 {$e->getMessage()}", $e->getTrace());
return view('auth.register')
->with([
'email' => $request->email
])->withErrors(['error' => 'メールアドレスの登録に失敗しました。']);
}
Mail::to($request->email)->send(new \App\Mail\EmailVerification($emailVerification));
return view('auth.email_verify');
}
}
メールを送る処理は参考にした記事のように実装します。
これで、email_verifications
に仮会員登録を行い、登録したメールアドレスに認証用のメールが送られてきます。
###本会員登録処理を実装する
仮会員登録をした時に送られてきたメール認証用のURLをクリックして認証を行い本登録用にパスワードの設定を行います。
####メールアドレスの認証を行う
認証用のrouteを設定する
Route::get('/verify/{token}', [
'as' => 'verify',
'uses' => 'Auth\RegisterController@emailVerifyComplete',
])->where('token','[A-Za-z0-9]+');
RegisterController.phpにメールアドレス認証完了用の処理を追加する
public function emailVerifyComplete($token)
{
// 有効なtokenか確認する
$emailVerification = EmailVerification::findByToken($token);
if (empty($emailVerification) || $emailVerification->isRegister()) {
return view('errors.email_verify');
}
// ステータスをメール認証済みに変更する
$emailVerification->mailVerify();
DB::beginTransaction();
try {
// DB更新
$emailVerification->update();
DB::commit();
} catch (\Throwable $e) {
DB::rollBack();
Log::warning("メールアドレスの認証に失敗しました: email: {$emailVerification->email}", $e->getTrace());
return redirect(route('/'))
->with(['message' => 'メールアドレスの認証に失敗しました。管理者にお問い合わせください。']);
}
return view('auth.pre_register')
->with(['token' => $emailVerification->token]);
}
EmailVerification.phpにも処理を追加しました。
public static function findByToken($token)
{
return self::where('token', '=', $token)->first();
}
public function mailVerify()
{
$this->status = self::MAIL_VERIFY;
}
public function isRegister()
{
return $this->status === self::REGISTER;
}
public function register()
{
$this->status = self::REGISTER;
}
これで仮会員登録まで完了しました。
####本会員登録用のviewを作る
仮会員登録完了した後にreturn view('auth.pre_register')
としたので、viewファイルを作成します。
<div class="main_inner form">
<h1 class="alignCenter">OK</h1>
<p class="alignCenter">
メールアドレスの認証が完了しました。
<br>
名前とパスワードを設定してください。
</p>
{!! Form::open(['route' => ['registered', $token], 'method' => 'post']) !!}
{{ csrf_field() }}
@if(session('message') OR isset($message))
<div class="success m-b2">
{!! session('message') ? session('message') : $message !!}
</div>
@endif
@if(session('error'))
<div class="end m-b2">
{!! session('error') !!}
</div>
@endif
@if (count($errors) > 0)
<ul class="end">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endif
<p class="bold m-t3">名前</p>
<p>{{ Form::text('name', null, ['placeholder' => '名前', 'required']) }}</p>
<p class="bold m-t3">パスワード</p>
<p>{{ Form::password('password', ['placeholder' => 'パスワード', 'required']) }}</p>
<p class="bold m-t3">確認用パスワード</p>
<p>{{ Form::password('password_confirmation', ['placeholder' => '確認用パスワード', 'required']) }}</p>
<div class="m-t3">{{ Form::submit('登録する', ['class' => 'btn']) }}</div>
{!! Form::close() !!}
</div>
auth/register.blade.phpのformの部分だけ書き換えて作成しました。
これで本会員登録用の入力フォームが完成しました。
####登録処理を実装する
次に、登録ボタンを押した時の遷移先をweb.php
に追加します。
入力フォームのpost先は
['route' => ['registered', $token], 'method' => 'post']
にしたのでこれに対応するrouteを追記します。
Route::post('/verify/{token}',[
'as' => 'registered',
'uses' => 'Auth\RegisterController@create',
])->where('token','[A-Za-z0-9]+');
routeに追加したので次は、Controllerに本会員登録の処理を追加していきます。
protected function create_validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|max:255',
'password' => 'required|string|min:6|confirmed',
]);
}
protected function create(Request $request, $token)
{
$validator = $this->create_validator($request->all());
if ($validator->fails()) {
return view('auth.pre_register')
->with([
'token' => $request->token,
'name' => $request->name,
])
->withErrors($validator);
} else {
$emailVerification = EmailVerification::findByToken($token);
$user = User::create([
'name' => $request->name,
'email' => $emailVerification->email,
'password' => Hash::make($request->password),
]);
$emailVerification->register();
$emailVerification->update();
Auth::login($user);
return redirect()->route('home');
}
}
本会員登録時のvalidationでエラーが発生した場合は、パスワード以外のパラメータを返しておきます。
本会員用のvalidation処理と登録処理を追加しました。
カラムもmake:auth
で実行した時に作成される分しか使用しなかったので特に追加する必要はありません。
###実装完了です
今回、本会員登録後のviewは作成しなかったので作成されているhome
を表示するようにしました。
Laravelを触ったのが今回初めてだったので、分からないことがたくさんあり調べつつ実装していきました。
せっかく新しいFWを書いたので備忘録も兼ねて初めてまとめてみました。
もっと実務でも書けるように勉強していきたいと思います!
ありがとうございました。
###参考
今回の実装をするに当たって以下のqiita記事を参考にして作成しました。
[Laravel]メール認証を使った会員登録