0.環境
今回のこの記事を書いた環境
OS...Windows 10
IDE...Eclipse 2020-3
Java...Open JDK 14
サーブレットコンテナ...Apache Tomcat 9.0.33
1.reCAPTCHAを作成する
まずreCAPTCHAのサイトにアクセスします。
reCAPTCHA
+ボタンで作成。
自分のサイトの情報を入力していきます。
ラベルにはわかりやすい名前を入力します。
reCAPTCHA タイプは、「私はロボットではありません」をやりたいのでreCAPTCHA v2を選択。
すると、「私はロボットではありません」チェックボックスというのが出てきますので選択されていることを確認します。
ドメインは「私はロボットではありません」を設定するドメインを入力します。
一番上のドメインを登録しておけばサブドメインでも使えます。
開発環境でも使う場合は「localhost」も登録してやりましょう。
オーナーは…まぁ好きなようにすれば良いでしょう。
最後にreCAPTCHA 利用規約に同意して、アラートをオーナーに送信するか選択したら送信をクリック
次の画面で2つの文字列が表示されるので両方ともメモっておきます。
2.Eclipseで新しいプロジェクトを作成する
今回は「RecaptchaTest」にします。
(もう既に作ってある場合はそれを使ってください。)
3.HTML作成
Eclipseで作成したプロジェクトのWebContentに新しいHTMLファイルを作成しましょう。
もしくは外部のエディターで作ってプロジェクト内に貼り付けても問題無いでしょう。
普段こんなクソコード書かないんですがまぁ今回はサンプルなので。。。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>reCAPTCHAのサンプル</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
<form action="login" method="post">
ID:<input type="text" name="id"><br>
パスワード:<input type="password" name="current-password">
<div class="g-recaptcha" data-sitekey="[ここにさっき表示された2つの文字列のうち、上のボックスに入ってた文字列を入れる]"></div>
<input type="submit" value="ログイン">
</form>
</body>
</html>
大事なのはheadのscriptを読み込む事と、formの中に
<div class="g-recaptcha" data-sitekey="[さっき表示された上のボックスに書いてあったやつ]">
を入れる事。
このdivを入れたところにあの「私はロボットではありません」のやつが表示されることになります。
んで、上のHTMLを完成させたら試しにサーバで実行してみましょう。
下の画像のようになればここまでおkです!!
4.クラス作成
GoogleのreCAPTCHAに結果を問い合わせるクラス(モデル)を作りましょう。
仕組みは簡単で決められたURLに決められたパラメータを乗せてPOSTしたらレスポンスでJSONが帰ってくる。
以下のコードのSECRET_KEYを自分で取得した文字列に変えましょうね~~~
package com.sakurai_shinya.recaptcha;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class RecaptchaAuthenticator {
private static final String URL = "https://www.google.com/recaptcha/api/siteverify";
private static final String SECRET_KEY = "[下のボックスに入っていた文字列]";
public static boolean checkRecaptcha(String userToken) throws IOException {
String recaptchaResponse = post(new URL(URL), "secret=" + SECRET_KEY + "&response=" + userToken);
return recaptchaResponse.contains("\"success\": true,");
}
private static String post(URL url, String parameters) throws IOException {
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setDoOutput(true);
try (DataOutputStream dos = new DataOutputStream(con.getOutputStream())) {
dos.writeBytes(parameters);
dos.flush();
}
if (con.getResponseCode() != 200) {
throw new IOException("サーバとの通信でエラーが発生しました。");
}
StringBuilder sb = new StringBuilder();
try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
String tempStr;
while ((tempStr = in.readLine()) != null) {
sb.append(tempStr);
}
}
return sb.toString();
}
}
面倒くさいのでレスポンスをcontainsで「"success": true,」が入ってたらOK、入ってなかったらNGって作った。
ちゃんとやるならちゃんとオブジェクト作ってパースしてって作った方が良いよねぇ
5.コントローラー(Servlet)作成
サーブレットのコード一応全部乗せておくけどPOSTのところだけしかいらない。
というかPOSTのところだけ見ろ
package com.sakurai_shinya.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sakurai_shinya.recaptcha.RecaptchaAuthenticator;
@WebServlet("/login")
public class Login extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
super.service(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.sendRedirect("login.html");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
boolean recaptchaResult = false;
try {
recaptchaResult = RecaptchaAuthenticator.checkRecaptcha(request.getParameter("g-recaptcha-response"));
} catch (IOException e) {
response.getWriter().append("reCAPTCHA認証サーバの通信でエラーが発生しました。" + e.toString());
}
if (recaptchaResult) {// reCAPTCHA成功
// ここにIDとパスワードを照合する処理。
String inputId = request.getParameter("id");
String inputPass = request.getParameter("current-password");
response.getWriter().append("reCAPTCHA認証に成功。<br>ID:" + inputId + "<br>パスワード:" + inputPass);
} else {// reCAPTCHA失敗
response.getWriter().append("reCAPTCHA認証に失敗しました。");
}
}
}
RecaptchaAuthenticator.checkRecaptcha(request.getParameter("g-recaptcha-response"));
さっき作ったクラスのcheckRecaptchaを呼び出すと結果がtrueかfalseか例外で帰ってくるからtrueだったらreCAPTCHA成功、falseだったらreCAPTCHA失敗、例外はエラーってことになる。
ちなみにg-recaptchaのやつをformに貼るとg-recaptcha-responseってパラメータが不思議な力で一緒にPOSTされるようになる。
これをGoogleのサーバに送ってユーザを特定するんですね~~~
6.テスト
こうしてチェックを入れた場合とチェックを入れなかった場合でテストしてみてください!
7.おまけ
7-1.黒くする方法
g-recaptchaを持ってるやつにdata-theme=darkを追加すると黒くなります。
これで黒いサイトでもかっこよく配置できる!!
<div class="g-recaptcha" data-sitekey="6Lfx-eMUAAAAALrP774ZrvQa_AtguQhusF0M2W6s" data-theme="dark"></div>
こんな感じ↓
7-2.英語にする方法
api.jsのGETパラメータにhl=enをつけると英語になります。
<script src="https://www.google.com/recaptcha/api.js?hl=en" async defer></script>
変な位置で勝手に改行される日本語とは違ってスタイリッシュな印象になりますね~
ちなみに他の言語はreCAPTCHAのガイドに乗ってます。
Language Codes | reCAPTCHA | Google Developers