試作しているLaravel5.7+Vue.jsのWebアプリでreCAPTCHAv2をログイン画面に追加してみたので、何をどうしたのかメモしておきます。
……まだLaravelの仕組みを良く分かっていないので、書いておかないと後で忘れそうなので。
前提
今回は以下のことを前提とします
- ログイン画面は
php artisan make:auth
で生成されたものをベースとするが、カスタマイズを施してあるものとする
実装
では、実際に行ったことを以下に記します。
composer.json
"require": {
//略
"anhskohbo/no-captcha": "^3.0",
//略
}
anhskohbo/no-captcha
というライブラリを使用することは決まっているので、まずは
composer require anhskohbo/no-captcha
します。
コマンド
続いて以下のコマンドを実行します。
> php artisan vendor:publish --provider="Anhskohbo\NoCaptcha\NoCaptchaServiceProvider"
Copied File [\vendor\anhskohbo\no-captcha\src\config\captcha.php] To [\config\captcha.php]
Publishing complete.
これで設定ファイルをPublishします。
config/captcha.php
に以下の内容がセットされると思います。
<?php
return [
'secret' => env('NOCAPTCHA_SECRET'),
'sitekey' => env('NOCAPTCHA_SITEKEY'),
'options' => [
'timeout' => 30,
],
];
reCAPTCHAサイトでの登録
GoogleのreCAPTCHAサイトで使用するreCAPTCHAの情報を登録します。v2でチェックボックス、ドメインは
localhost
と本番用ドメインの2つを追加で。
.envにサイトキーとシークレットキーを追加
config/captcha.php
で指定された名前でサイトキーとシークレットキーを
.env
にセットします。
NOCAPTCHA_SITEKEY=xxxxxxxxxxxxxxx
NOCAPTCHA_SECRET=xxxxxxxxxxxxxxx
ルータにルーティングを追加
今回のルーティング(
routes/web.php
)は下記の通りとします。
Route::get('/', function () {
return redirect('/home');
})->middleware('auth');
Route::get('/login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('/login', 'Auth\LoginController@login');
ログインフォーム(
/login
)から自分自身へリクエストを投げて、成功したら
/home
へリダイレクト。
login.blade.php
<form method="POST" action="{{ route('login') }}" class="container">
@csrf
<div class="form-row mb-3">
<div class="col">
<label for="userid">{{ __('ユーザID') }}</label>
<input type="text" class="form-control{{ $errors->has('userid') ? ' is-invalid' : '' }}" id="userid" name="userid" required autofocus>
@if ($errors->has('userid'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('userid') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-row my-3">
<div class="col">
<label for="password">{{ __('パスワード') }}</label>
<input type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" id="password" required>
@if ($errors->has('password'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group my-3">
<div class="col">
<label for="recaptcha">{{ __('reCAPTCHA') }}</label>
{!! NoCaptcha::display() !!}
@if ($errors->has('recaptcha'))
<span class="invalid-feedback" role="alert">
<strong>{{ __('reCAPTCHAにチェックを入れて下さい') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-row my-4">
<div class="col text-center">
<button type="submit" class="btn btn-success shadow-sm px-4" id="sugmit">{{ __('ログイン') }}</button>
</div>
</div>
</form>
ログインフォームはこのような感じで。仮なのでエラーメッセージは直書き。後で
resources/lang/ja/
以下にファイルを追加して修正する予定。
肝はreCAPTCHA用の部分の
{!! NoCaptcha::display() !!}
。これでreCAPTCHAを表示させている。
<script src="./js/app.js"></script>
{!! NoCaptcha::renderJs() !!}
ちなみにJS読み込み部分は上記のように。
{!! NoCaptcha::renderJs() !!}
でreCAPTCHA用のJSを読み込ませる形に。
LoginController.php
app/Http/Controllers/Auth/LoginController.php
にログインを制御する内容を記述。
<?php
namespace App\Http\Controllers\Auth;
//追加分
use Validator;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
//元々あるもの
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
//略
public function username()
{
return 'userid';
}
public function login(Request $request)
{
//バリデーション
$validator = Validator::make($request->all(), [
$this->username() => 'required',
'password' => 'required',
'g-recaptcha-response' => 'required|captcha' //reCAPTCHA評価
]);
//認証
$credentials = $request->only($this->username(), 'password');
if (!$validator->fails() && Auth::attempt($credentials)) { //バリデーションと認証の両方が成功
return redirect('/home');
}
else { //失敗
//エラー処理
}
}
こんな感じ。不恰好ですが、参考サイトではreCAPTCHAの成否判定に
Validator
を使用しており、一方でID・パスワードの認証は
Auth::attempt
しか思い付かなかったのでこんな実装に。
もっと上手い書き方があるとは思うのですが、これでとりあえず動作要件は満たせました。
参考
Laravelの認証
Laravel + reCAPTCHAv2