LaravelでReCAPTCHAを複数の処理で使用する方法
いつもご利用ありがとうございます。
この記事には広告が掲載されており、その広告費によって運営しています。
Laravel で ReCAPTCHA を Ajax や axios などを使って、複数の処理で使用する方法についてまとめました。
例えば、1 の方を非同期でやりたい場合に使います。
- メールアドレスがユニークか(すでに登録されたものじゃないか)確認するだけの処理
- ユーザー登録
このような仕様にしたい際に、ユニークの確認をボットに検証され続けるのを避けるために必要になりました。
ReCAPTCHA を使用する方法
ReCAPTCHA は、一度その token を使うともう同じ物は使えなくなるので、再生成する必要があります。
なので、「使用したら再生成」するコードを実行すれば、Vue であろうと jQuery であろうと動きます。
今回紹介する方法は、blade での実装ですが、View ファイルのサイトキーの変数の管理をアレンジするだけで転用が可能です。
まず、サイトキーとシークレットキーの取得
GCP に登録して、サイトキーとシークレットキーを取得します。
今回は、V3 で取得しました。
.env と config に追記
.env
RECAPTCHA_SITEKEY=6LdfKoMfAAAAAL*********
RECAPTCHA_SECRET=6LdfKoMfAAAAAPd********
config/services.php
<?php
return [
// ~~略
'recaptcha' => [
'sitekey' => env('RECAPTCHA_SITEKEY'),
'secret' => env('RECAPTCHA_SECRET'),
],
];
Rule の作成
カスタムのバリデーションルールを作成します。
php artisan make:rule ReCaptcha
app/Rules/ReCaptcha.php
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Facades\Http; //追記
class ReCaptcha implements ValidationRule
{
/**
* Run the validation rule.
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$response = Http::get("https://www.google.com/recaptcha/api/siteverify",[
'secret' => config('services.recaptcha.secret'),
'response' => $value
]);
if (!($response->json()["success"] ?? false)) {
$fail('GoogleRecaptchaは必須です');
}
}
}
使用するページで読み込み
CDN から Script を読み込みます。
<script src="https://www.google.com/recaptcha/api.js?render={{ config('services.recaptcha.sitekey') }}"></script>
使用したいフォームの中に、任意の id を付与した input タグを追記します。
<form>
<!-- 略 -->
<input id="g-recaptcha-response" type="hidden" name="g-recaptcha-response" />
</form>
初期化
<script>
//初期化
grecaptcha.ready(function () {
reloadRecaptchaToken()
})
//tokenを取得し、隠しinputタグのvalueへ
function reloadRecaptchaToken() {
grecaptcha.execute({{ config('services.recaptcha.sitekey') }}, { action: "login" }).then(token => {
$("#g-recaptcha-response").val(token)
})
}
</script>
バリデーションの追記
FormRequest
や、LoginController
などで、先ほど作成した Rule を使ってバリデーションを指定します。
use App\Rules\ReCaptcha;
//~~略
public function rules()
{
return [
'email' => 'required|string|email|max:100',
'g-recaptcha-response' => ['required', new ReCaptcha]
];
}
以上で ReCAPTCHA の設定が完了し、使えるようになりました。
複数の処理で ReCAPTCHA を使用する方法
ここまで実装できていれば、ほとんどやることはありません。
token を再生成してあげれば良いだけです。
token の再生成は、
function reloadRecaptchaToken() {
grecaptcha.execute({{ config('services.recaptcha.sitekey') }}, { action: "login" }).then(token => {
$("#g-recaptcha-response").val(token)
})
}
ここで関数を作っているので、この関数を再度動かせば OK です。
Axios だとこんな感じで再生成してあげれば OK です。
axios
.post("/api/check-email", {
email: "sample@example.com",
"g-recaptcha-response": document.getElementById("g-recaptcha-response")
.value,
})
.then()
.catch()
.finally(() => {
reloadRecaptchaToken() //再生成
})
Ajax だと
$.ajax({
url: "/api/check-email",
method: "POST",
data: {
email: 'sample@example.com',
'g-recaptcha-response': document.getElementById('g-recaptcha-response').value
}
success: function (response) {},
error: function (jqXHR, textStatus, errorThrown) {},
complete: function () {
reloadRecaptchaToken() //再生成
},
})
成功しても失敗しても再生成しておきます。
まとめ
以上です。
誰かの参考になればと思います。