Languages
[Edit]
PL

reCAPTCHA v3 - przykład użycia w JavaScript z Framework-iem Spring

12 points
Created by:
Inferio
268

W tym artykule chcielibysmy pokaza─ç w jaki spos├│b u┼╝ywa─ç┬áGoogle reCAPTCHA v3┬áw po┼é─ůczeniu┬áJavaScript po stronie przegl─ůdarki oraz┬áSpring Frameworku po stronie backendu.

Artykuł składa się z 3 częsci:

  • opisu przyk┼éadowej konfiguracji w panelu Google reCAPTCHA v3,
  • przyk┼éadowy kod dzia┼éaj─ůcy po stronie przegl─ůdarki (front-end),
  • przyk┼éadowy kod dzia┼éaj─ůcy po stronie serwera (back-end).

Oficjalna dokumentacja dla reCAPTCHA v3 znajduje się tutaj.

 

Wykonaj nastepuj─ůce kroki

  1. konfiguracja Google reCAPTCHA:
    1. wejdź do panelu Google reCAPTCHA
      https://www.google.com/recaptcha/admin#list
    2. utw├│rz now─ů konfuguracj─Ö,
    3. wprowad┼║ wymagane dane (znajduj─ů si─Ö one ni┼╝ej na zrzucie ekranu):
      1. Label (wprowad┼║ swoj─ů nazw─Ö konfiguracji),
      2. reCAPTCHA type ustaw jako v3,
      3. Domains┬ázawiera┬ámy-domain.com, kt├│re nale┼╝y zast─ůpi─ç nazw─ů swojej domeny oraz dodatkowo┬álocalhost, aby m├│c testowa─ç aplikacj─Ö w trakcie dewelopmentu,
    4. zaakceptuj regulamin i kliknij Submit,
  2. integracja przyk┼éadowych kod├│w z twoj─ů stron─ů,
    1. skopiuj kody ┼║r├│d┼éowe znajduj─ůce w dalszej cz─Ösci artyku┼éu,
    2. skopiuj┬ásite key┬ádo pliku┬áindex.html┬á(nale┼╝y zamieni─ç klucz┬ásite_key_xxyyzz w dwuch miejscach┬á- parametr w url oraz zmienn─ů w kodzie):
      <script src="https://www.google.com/recaptcha/api.js?render=site_key_xxyyzz"></script>
      var PUBLIC_KEY = 'site_key_xxyyzz';
    3. skopiuj secret key do pliku ReCAPTCHAv3Utils.java:
      private static final String SECRET_KEY = "secret_key_xxyyzz";
  3. otw├│rz w przegl─ůdarce swoj─ů stron─Ö i sprawd┼║ czy wszystk odzia┼éa poprawnie.

Porady:

  • nie udost─Öpniaj swojego┬ásecret key!
  • ustaw┬ádouble SCORES_LEVEL = 0.7┬ázgodnie ze swoimi wymaganiami (opis znajdziesz poni┼╝ej w kodzie),
  • czasami dobrze jest wykona─ç pewn─ů akcj─Ö je┼Ťli dojedzie do wykrycia zachowania, kt├│re wsjkazuj─Ö na u┼╝ycie bota (przyk┼éadowo odczekaj 60 sekund lub popro┼Ť u┼╝ytkownika o potwierdzenie swojej to┼╝samo┼Ťci np. swoim mailem lub nr. telefonu).

 

Przykładowa konfuguracja panelu Google reCAPTCHA v3 

W tej sekcji zamieszczono przyk┼é─ůdow─ů konfiguracj─Ö u┼╝yt─ů┬ápodczas tworzenia┬áreCAPTCHA v3. Poni┼╝szy zrzut ekranu jest w j─Özyku angielskim ze wzgl─Ödu na to, ┼╝e sam panel nie ma t┼éumaczenia na j─Özyk polski.

Wskaz├│wka: nie zapomnij doda─ç domeny┬álocalhost┬áje┼Ťli chcesz dewelopowa─ç apliacj─Ö lokalnie z u┼╝yciem┬áreCAPTCHA.

Rejestracja reCAPTCHA v3.
Rejestracja reCAPTCHA v3.
site key + secret key dla reCAPTCHA v3
site key + secret key dla reCAPTCHA v3

 

Przyk┼éadowy┬ákod┬áJavaScript wykonywany┬áw przegl─ůdarce (Front-end)

W tej sekcji przedstawiono przyk┼é─ůd u┼╝ycia┬áreCAPTCHA v3┬ádla scenariusza logowania u┼╝ytkownika - kod JavaScript. Tekst reprezetuj─ůcy akcj─Ö┬álogin┬ámo┼╝emy zamieni─ç na cokolwiek (znajduje si─Ö on w linijce zawieraj─ůcej: ReCAPTCHAv3Utils.request('login', onSuccess, onError)).

index.html file:

// ONLINE-RUNNER:browser;

<!doctype html>
<html>
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
  <!-- klucz reCaptcha v3 mo┼╝na uzysk─ů─ç na stronie https://www.google.com/recaptcha/admin#list -->
  <script src='https://www.google.com/recaptcha/api.js?render=site_key_xxyyzz&hl=pl'></script>
</head>
<body>
  <script>

    /*
        panel reCaptcha v3:
            https://www.google.com/recaptcha/admin#list

        dokumentacja reCaptcha v3:
            https://developers.google.com/recaptcha/docs/v3
    */
    var ReCAPTCHAv3Utils = new function() {

        // klucz reCaptcha v3 mo┼╝na uzysk─ů─ç na stronie https://www.google.com/recaptcha/admin#list
        var PUBLIC_KEY = 'site_key_xxyyzz';

        // Odpytuje Google reCAPTCHAv3 API w celu uzyskania tokenu.
        //
        // argumenty:
        //     action - mo┼╝ymy wstawi─ç tutaj dowolny tekst nazywaj─ůcy nasz─ů akcj─Ö
        //         Rzu─ç okiem na "Use case" stronie https://developers.google.com/recaptcha/docs/v3
        //         przykładowno można uzyć. homepage, login, social, e-commerce
        //     onSuccess i onError - to funkcje callback, kt├│re wykonywane s─ů ajko rezultat zapytania
        //
        this.request = function(action, onSuccess, onError) {
            if (window.grecaptcha) {
                window.grecaptcha.ready(function() {
                    var config = {
                        action : action
                    };
                    try {
                        var query = window.grecaptcha.execute(PUBLIC_KEY, config);
                        if (onSuccess) {
                            query.then(onSuccess);
                        }
                    } catch (e) {
                        var message = e && e.message || 'Bład zapytania reCAPTCHA.';
                        if (onError) {
                            onError(message);
                        }
                    }
                });
            } else {
                if (onError) {
                    onError('reCAPTCHA v3 nie została załadowana poprawnie.');
                }
            }
        };
    };
    
    
    // Przykład użycia:

    function loginUser(data) {
        var onSuccess = function(token) {
            data.token = token; // <------- przyznany token przez Google reCAPTCHA v3
            $.ajax({
                type: 'POST',
                url: '/backend/login-user',
                data: JSON.stringify(data),
                contentType : 'application/json; charset=utf-8',
                dataType : 'json',
                success: function(data) {
                    alert('Odpowied┼║: ' + data.message);
                },
                error: function(error) {
                    alert('B┼é─ůd zapytania!');
                }
            });
        };
        var onError = function(message) {
            alert('B┼é─ůd: ' + message);
        };
        ReCAPTCHAv3Utils.request('login', onSuccess, onError);
    }

    loginUser({
        username: 'John',
        password: 'my-password-here'
    });

  </script>
</body>
</html>

 

Przykładowy kod Java wykonywany w frameworku Spring Framework (Back-end)

W tej sekcji zaprezentowano przyk┼éadowy kod w jezyku Java za pomoc─ů, kt├│rego jeste┼Ťmy w stanie razem z frameworkiem Spring wykona─ç zapytanie do Google-owego API┬áreCAPTCHA v3┬áw celu zweryfikowania zachowania u┼╝ytkownika - czy jest to bot lub cz┼éowiek.

Poni┼╝ej przedstawiono kilka plik├│w, kt├│re nale┼╝y umie┼Ťci─ç w swoim projekcie.

Plik┬ápom.xml┬á(wymagana do dodania zale┼╝no┼Ť─ç dla maven-a):

<!-- Jackson JSON Mapper -->
<dependency>
	<groupId>org.codehaus.jackson</groupId>
	<artifactId>jackson-mapper-asl</artifactId>
	<version>1.9.10</version>
</dependency>

Plik UserController.java:

package logic.controller_captcha;

import logic.util.LoggerUtil;
import org.apache.log4j.Logger;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import logic.controller_captcha.recaptchav3.ReCAPTCHAv3Exception;
import logic.controller_captcha.recaptchav3.ReCAPTCHAv3Utils;
import logic.controller_captcha.recaptchav3.ReCAPTCHAv3Response;

@Controller
public class UserController {

    private final Logger logger = Logger.getLogger(getClass());

    // w zakresie od 0.0 do 1.0
    //  1.0 wskazuj─Ö na bardzo dobr─ů inteakcj─Ö rzczeczywistego u┼╝ytkownika
    //  0.0 wskazuje na 100%, ┼╝e jest to zachwoanie typu bot
    private final static double SCORES_LEVEL = 0.7;

    @RequestMapping(value = "/backend/login-user", method = RequestMethod.POST)
    @ResponseBody
    public String loginUser(
            HttpServletRequest request, 
            @RequestBody LoginUserRequest loginUserRequest
    ) {
        String token = loginUserRequest.getToken();
        String address = request.getRemoteAddr();

        try {
            ReCAPTCHAv3Response response = ReCAPTCHAv3Utils.request(token, address);
            if (response.getSuccess()) {
                if (response.getScore() > SCORES_LEVEL) {
                    // some login operation here ...
                    return "{\"message\": \"Logowanie zakończone sukcesem.\"}";
                } else {
                    return "{\"message\": \"Wykryto dziwne zachowanie.\"}";
                }
            }
            return "{\"message\": \"Adres lub token jest niepoprawny.\"}";
        } catch (ReCAPTCHAv3Exception e) {
            return "{\"message\": \"B┼é─ůd reCAPTCHA.\"}";
        }
    }
}

Plik LoginUserRequest.java:

package logic.controller_captcha;

public class LoginUserRequest
{
    private String token;


    // wstaw tutaj pozostałe pola ...


    public String getToken() {
        return this.token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}

Plik ReCAPTCHAv3Utils.java:

package logic.controller_captcha.recaptchav3;

import org.codehaus.jackson.map.ObjectMapper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

/*
    panel reCaptcha v3:
        https://www.google.com/recaptcha/admin#list

    dokumentacja reCaptcha v3:
        https://developers.google.com/recaptcha/docs/v3
*/
public final class ReCAPTCHAv3Utils {

    private static ObjectMapper mapper = new ObjectMapper();

    // klucz do reCaptcha v3 mo┼╝na uzyska─ç na stronie https://www.google.com/recaptcha/admin#list
	private static final String SECRET_KEY = "secret_key_xxyyzz";

    private ReCAPTCHAv3Utils() {
        // pusty konstruktor ...
    }

    private static String readStream(InputStream stream) throws IOException {
        StringBuilder builder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
            while (true) {
                String line = reader.readLine();
                if (line == null) {
                    break;
                }
                builder.append(line);
            }
        }
        return builder.toString();
    }

    private static ReCAPTCHAv3Response readObject(InputStream stream) throws IOException {
        String response = readStream(stream);
        return mapper.readValue(response, ReCAPTCHAv3Response.class);
    }

    public static ReCAPTCHAv3Response request(String token, String ip) throws ReCAPTCHAv3Exception {
        try {
            URL url = new URL("https://www.google.com/recaptcha/api/siteverify?secret=" 
                + SECRET_KEY + "&response=" + token + "&remoteip=" + ip);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            try {
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(10000);
                connection.setReadTimeout(10000);
                return readObject(connection.getInputStream());
            } finally {
                connection.disconnect();
            }
        } catch (Exception e) {
            throw new ReCAPTCHAv3Exception("B┼é─ůd dla zapytania reCAPTCHA.", e);
        }
    }
}

Plik ReCAPTCHAv3Exception.java:

package logic.controller_captcha.recaptchav3;

public class ReCAPTCHAv3Exception extends Throwable {

    public ReCAPTCHAv3Exception(String message) {
        super( message );
    }

    public ReCAPTCHAv3Exception(String message, Throwable cause) {
        super( message, cause );
    }
}

Plik ReCAPTCHAv3Response.java:

package logic.controller_captcha.recaptchav3;

import org.codehaus.jackson.annotate.JsonProperty;

public class ReCAPTCHAv3Response {

    @JsonProperty( "success" )
    private boolean success;

    @JsonProperty( "score" )
    private double score;

    @JsonProperty( "action" )
    private String action;

    @JsonProperty( "challenge_ts" )
    private Object timestamp;

    @JsonProperty( "hostname" )
    private String hostname;

    @JsonProperty( "error-codes" )
    private Object errors;

    public boolean getSuccess() {
        return this.success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public double getScore() {
        return this.score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public String getAction() {
        return this.action;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public String getHostname() {
        return this.hostname;
    }

    public void setHostname(String hostname) {
        this.hostname = hostname;
    }
}
Native Advertising
­čÜÇ
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

ÔŁĄ´ŞĆ­čĺ╗ ­čÖé

Join