reCAPTCHA v3 × Laravel

#Laravel5.7にreCAPTCHAv3を導入する手順
v3導入にあたって、
①
・[anhskohbo/no-captcha](https://github.com/anhskohbo/no-captcha/blob/master/README.md) 
・[ARCANEDEV/noCAPTCHA](https://github.com/ARCANEDEV/noCAPTCHA/blob/master/README.md) 
どちらのライブラリを使えば良いの？？問題

（結論としては今回はARCANEDEV/noCAPTCHA
になります。これはLaravelの4.2~7.xまでサポートしているようなので、今回は5.7で検証していますが、他のバージョンでも同様にいけるはずです。）


②
reCAPTCHAのトークンは二分間しか持たない問題
> Note: reCAPTCHA tokens expire after two minutes. If you're protecting an action with reCAPTCHA, make sure to call execute when the user takes the action.
[Google reCAPTCHA](https://www.google.com/recaptcha/intro/v3.html) 

上記２点に主に焦点を当てて導入手順を述べていきたいと思います。

##目次
1. [reCAPTCHAとは？](#link_1)
2. [サイトキー（SITEKEY）とシークレットキー(SECRETKEY)の取得](#link_2)
3. [composerでライブラリをインストール](#link_3)
4. [フロントエンド](#link_4)
5. [バックエンド](#link_5)


<a id="link_1"></a>
###reCAPTCHAとは？
[Google reCAPTCHA](https://www.google.com/recaptcha/intro/v3.html) 
人間になりすましてBOTが操作していないかチェックしてくれる,Googleのサービス。
「私はロボットではありません」のあれです。


このreCAPTCHA
v1,v2 とあるなかで　2018/10/29からv3になっています。
v2とv3の違いについてはググるとすぐにわかるのでここでは省きますが、
ユーザーが**チェックを入れる必要がなくなった**という事実はv3導入において一つのポイントになります。

<a id="link_2"></a>
###サイトキー（SITEKEY）とシークレットキー（SECRETKEY）の取得
[Google reCAPTCHA Developer's Guide](https://developers.google.com/recaptcha/intro)
↑ここに大まかな実装方法は書いてあります

[サイトキー（SITEKEY）とシークレットキー（SECRETKEY）の取得はこちらから](https://www.google.com/recaptcha/admin/create)
↑ここにreCAPTCHAを適用したいサイトを載せます。
**主な各項目について**
・**ラベル** :
ここはサイトに対するニックネーム的扱いです。（自分がわかればなんでも良いです。）
・**reCAPTCHAタイプ** :
今回はv3を利用するのでv3にチェックを入れます。
・**ドメイン** :
普通にドメインを登録すれば良いのですが、開発環境で確認したい場合はlocalhostではなく、
```127.0.0.1
```
で登録をして進めてください。

これで登録が完了すると
・サイトキー(SITEKEY)
・シークレットキー(SECRETKEY)
が発行されます。
あとはライブラリと組み合わせて
実装を進めます。


<a id="link_3"></a>
###composerでライブラリのインストール
・[ARCANEDEV/noCAPTCHA](https://github.com/ARCANEDEV/noCAPTCHA/blob/master/README.md)
をcomposerでインストールします。
[Laravelのバージョンに応じてnoCAPTCHAのインストールのバージョンを確認してください](https://github.com/ARCANEDEV/noCAPTCHA/blob/master/_docs/1-Installation-and-Setup.md)
今回はLaravel5.7なので

```
composer require arcanedev/no-captcha:8.x
```
インストールしたら

```
php artisan vendor:publish --provider="Arcanedev\NoCaptcha\NoCaptchaServiceProvider"
```
でno-captchaのconfigファイルを呼び出して、
versionを示す部分が**v3**になっているか確認をします。(私はデフォルトでv3になっておりました。)

その後、先ほど所得した
SITEKEYとSECRETKEYを
.envファイルに

```
NOCAPTCHA_SECRET=your-secret-key
NOCAPTCHA_SITEKEY=your-site-key
```
と記述してセット



<a id="link_4"></a>
###フロントエンド
[Google reCaptcha フロントエンド](https://developers.google.com/recaptcha/docs/v3) 
↑公式の参照ページはこちら
公式にはざくっとこんな感じのことが記述されています。

> 1. Load the JavaScript API with your sitekey.
> 2. Call grecaptcha.execute on an action or when the page loads.
> 3. Send the token immediately to your backend with the request to verify.

１．まずJavaScript APIを読み込んでください。
２．イベント発火かあるいは、ページがロードされる際、"grecaptcha.execute"を呼び出すよう記述してください
3.すみやかにバックエンドにrequestと一緒にトークンを送り込んでください。

なんとなくここを意識しながらフロントエンドの実装にうつります。

```php:form.blade.php
<form id="form" action="{{ route('post')}}" method="POST">


    <button type="subbmit" id="form_btn">送信</button>
</form>
```

今回はNoCaptchaを使った時の書き方を以下に記述します。

reCAPTCHAを適用したいformの中に

```php:form.blade.php
<form id="form" action="{{ route('post')}}" method="POST">

    {!! no_captcha()->input() !!}

    <button type="subbmit" id="form_btn">送信</button>
</form>
```

と記述します。
これは以下とまったく同じ意味です。

```html
<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
```
あとで、javascriptこのinputタグに対して
valueにトークンをセットしてあげます。

そして```</body>```付近に

```php:form.blade.php
{!! no_captcha()->script() !!} 
```
これは以下と同じ意味になります。

```html

<script src="https://www.google.com/recaptcha/api.js?hl=jp&amp;render=SITE_KEY"></script>
```
v3のreCAPTCHAのイメージと、SITE_KEYをAPIに投げることで、当サイトがreCAPTCHAの保護対象かどうかを判断しています。

そして今回のポイントの一つ
reCAPTCHAのトークンは二分間しか持たない問題
> Note: reCAPTCHA tokens expire after two minutes. If you're protecting an action with reCAPTCHA, make sure to call execute when the user takes the action.


ここをクリアするために
少しjavascriptで工夫を懲らします。

```javascript

$(function () {
    $('#form_btn').on('click',function (e){
        if(confirm('本当に送信してもよろしいですか?')){
            e.preventDefault();
            grecaptcha.ready(function() {
                grecaptcha.execute('取得したサイトキー', {action: 'login'}).then(function(token) {
                    $('#g-recaptcha-response').val(token);
                    //ここでトークンを渡す。
                    $('#form').submit();
                });
            });    
        }
    });
});

```


<a id="link_5"></a>
###バックエンド
[Google Recapcha バリデーション](https://developers.google.com/recaptcha/docs/verify)
↑ここにバリデーションの方法など書いてます。
取得したSECRETKEYを用いて色々する必要があるのですが、
このあたりは
[ARCANEDEV/noCAPTCHA](https://github.com/ARCANEDEV/noCAPTCHA/blob/master/README.md) 
がとても楽にしてくれています。

私たちがやるべきことはコントローラでValidatorを利用してバリデーションルールを追加すれば良いだけ。

```php:FormController.php 
        $requests = $request->all();
        $rules = [
                // other 他のバリデーションルール
            'g-recaptcha-response' => ['required',new CaptchaRule]　//ここではrequiredとcaptchaを設定しております。
        ];
        $messages = [
             // 他にも
            'g-recaptcha-response.captcha' => 'reCaptchaによってうまく認証されませんでした'
        ];
        $validator = Validator::make($requests, $rules, $messages)->validate();

```

・requiredはトークンがセットされているかどうか
・captchaはトークンが有効かどうか

これで実装完了です。

###ちなみに…
・[anhskohbo/no-captcha](https://github.com/anhskohbo/no-captcha/blob/master/README.md) 
でも試したのですが、こちらでは私ではうまくできませんでした。
・READMEに、v３のサポートが明記されない
・インストールしてみましたが、参照URLがv2のものになっていた

もしかしたらconfigファイルをいじったりしたらうまくできるのかもしれませんが、それはまたの機会に。
PHP用にGoogleからもライブラリが出ているようなので今度はそちらでも試してみたいところです。

Qiita初投稿です。
記述に不備があればご指摘くださいますようよろしくお願いいたします。