🗯️
Cloudflare TurnstileをRails/Reactでライブラリを使って動かす
Cloudflare Turnstile
CAPTCHA の cloudfalre 版
Cloudflare Turnstileとはなんぞや?をより詳細な説明
Rails/Reactで動かしてみる
React
Reactでは、react-turnstileを利用します
Code
import { useCallback, useId, useState } from "react";
import Turnstile from "react-turnstile";
const App = () => {
const id = useId();
const [email, setEmail] = useState("");
const [token, setToken] = useState<string | null>(null);
// CAPTCHA完了時に取得したトークンを状態に保存
const handleCloudflareTurnstileTokenChange = (value: string | null) => {
setToken(value);
};
const handleSubmit = useCallback(
async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!token) {
alert("CAPTCHAを完了してください");
return;
}
// フォームの入力とCAPTCHAトークンをサーバーに送信
const res = await fetch("/api/test_turnstile", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
"cf-turnstile-response": token, // RailsのGem:rails-cloudflare-turnstileが params[:cf-turnstile-response]を参照しているので、そのまま送る
}),
});
if (res.ok) {
alert("送信完了!");
} else {
alert("送信に失敗しました");
}
},
[email, token]
);
return (
<main>
<section>
<h1>Cloudflare Turnstile テスト</h1>
<form onSubmit={handleSubmit}>
{/* Emailの入力欄 */}
<div>
<label htmlFor={`${id}-email`}>Email:</label>
<input
id={`${id}-email`}
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
{/* CAPTCHAウィジェット */}
<Turnstile
sitekey="YOUR_SITE_KEY"
onSuccess={handleCloudflareTurnstileTokenChange} //setTokenでもOK
/>
<button type="submit">送信</button>
</form>
</section>
</main>
);
};
export default App;
Rails
Railsは rails_cloudflare_turnstile
を使用します
導入方法はrails_cloudflare_turnstile
のRepositoryに書いてあるように
- Gemfileに
gem 'rails_cloudflare_turnstile'
を追加 - config/initializers/cloudflare_turnstile.rbを作成し、以下のような設定を追加
RailsCloudflareTurnstile.configure do |c|
c.site_key = "XXXXXX"
c.secret_key = "XXXXXXXX"
c.fail_open = true
end
- 利用Controllerに、
validate_cloudflare_turnstile
をbeforeに追加する
Code
class TestController < ApiController
rescue_from RailsCloudflareTurnstile::Forbidden, with: :cloudflare_turnstile_forbidden_error
before_action :validate_cloudflare_turnstile, only: [:create]
# Cloudflare Turnstileの認証に失敗した場合
def cloudflare_turnstile_forbidden_error
render status: :forbidden,
json: {
id: 'forbidden',
message: 'お手数ですが、Cloudflare Turnstileの認証を行い、再度送信してください。',
}
end
end
validate_cloudflare_turnstile
のメソッドがRequestの何を見てCloudflare Turnstileの成功・失敗を見ているか調べてみると
body = {
secret: config.secret_key,
response: params["cf-turnstile-response"],
remoteip: request.remote_ip
}
となっており、paramsの["cf-turnstile-response"]を参照して、Cloudflare Turnstileの成功・失敗を判別していました。
そのため、Reactでは、Cloudflare Turnstileを扱っている箇所のRequest時に cf-turnstile-response
をParameterに入れるようにしています。
つぶやき
Parameterで cf-turnstile-response
のようなケバブケースでのParameterはあんまり使ったことがなかったので、rails_cloudflare_turnstile
側で受け取るParameterを任意で設定出来るようになってると良かったなと思いました...
Discussion