Languages
[Edit]
PL

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

12 points
Created by:
Inferio
328

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;
    }
}
Donate to Dirask
Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
Join to our subscribers to be up to date with content, news and offers.
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