Po pierwsze należy wygenerować indywidulany dla domeny (może być też localhost dla testów lokalnych) sitekey i secret –> Google reCAPTCHA

Integracja po stronie klienta
W formularzu dodajemy kod reCAPTCHA z wygenerowanym sitekey

<div class="form-group">
<div class="g-recaptcha" data-sitekey="6Lf7anUUAAAAAHobMeDJkbR_xxxasasasa"></div>
</div>

Następnie w komponencie z formularzem w metodzie ngOnInit() dodajemy do strony skrypt z api reCAPTCHA. Jeśli skrypt zostałby dodany do index.html, to reCAPTCHA pojawiałaby się tylko po odświeżeniu strony.

ngOnInit(){ this.addScript(); }
	addScript() {
    let script = document.createElement('script');
    script.src = 'https://www.google.com/recaptcha/api.js';
    script.async = true;
    script.defer = true;
    document.body.appendChild(script);
}

Przed wysłaniem formularza należy sprawdzić czy pole “Nie jestem robotem” zostało zaznaczone.

onSubmit() {
    this.submitted = true;
	 const response = grecaptcha.getResponse();
         if (response.length === 0) {
            alert('Recaptcha not verified.');
            return;
        }
    this.save(); 
  }
	
	save() { 
    this.accountService.createNewUser(this.registerForm.value, grecaptcha.getResponse())
    .subscribe(
        data => { console.log(data); },
        error => { console.log(error); })
 }

Integracja po stronie serwera – tutaj przyda się przydzielony wcześniej kod secret

@PostMapping("/new")
	    @ResponseStatus(HttpStatus.CREATED)
		public void  createUser(@RequestBody UserDTO user, @RequestParam(name="response") String recaptchaResponse) {
	    	captchaVerification.verify(recaptchaResponse);
			userRepository.findByEmailIgnoreCase(user.getEmail())
			.ifPresent(u -> {throw new ResourceExistsException("User with login: "+user.getEmail()+" exist");});
	   	  	User createdUser = userService.createUser(user);
		}

Przed dodaniem nowego użytkownika do bazy danych należy sprawdzić poprawność recaptchaResponse, wysyłając zapytanie przez recaptcha api.

import java.net.URI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service("captchaVerification")
public class CaptchaVerification {

	 	@Autowired
	    private CaptchaSettings captchaSettings;

	 	public void verify(String response) {
       
        URI verifyUri = URI.create(String.format(
          "https://www.google.com/recaptcha/api/siteverify?secret=%s&response=%s",
          captchaSettings.getSecret(), response));
        
        RestTemplate restTemplate = new RestTemplate();
        GoogleResponse googleResponse = restTemplate.getForObject(verifyUri, GoogleResponse.class);
 
        if(!googleResponse.isSuccess()) {
            throw new InvalidRecaptchaException();
        }
    }
}

Sitekey i Secret umieszczone są w application.properties

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "google.recaptcha.key")
public class CaptchaSettings {
 
    private String site;
    private String secret;
    
	public String getSite() {
		return site;
	}
	public void setSite(String site) {
		this.site = site;
	}
	public String getSecret() {
		return secret;
	}
	public void setSecret(String secret) {
		this.secret = secret;
	}

}

Klasa GoogleResponse jest schematem reprezentującym odpowiedź przesłaną od Google Api i pomaga stwierdzić poprawność walidacji reCAPRTCHA.

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder({
    "success",
    "challenge_ts",
    "hostname",
    "error-codes"
})
public class GoogleResponse {

	 @JsonProperty("success")
	    private boolean success;
	     
	    @JsonProperty("challenge_ts")
	    private String challengeTs;
	     
	    @JsonProperty("hostname")
	    private String hostname;
	     
	    @JsonProperty("error-codes")
	    private ErrorCode[] errorCodes;
	 
	    @JsonIgnore
	    public boolean hasClientError() {
	        ErrorCode[] errors = getErrorCodes();
	        if(errors == null) {
	            return false;
	        }
	        for(ErrorCode error : errors) {
	            switch(error) {
	                case InvalidResponse:
	                case MissingResponse:
	                    return true;
	            }
	        }
	        return false;
	    }
	 
	    static enum ErrorCode {
	        MissingSecret,     InvalidSecret,
	        MissingResponse,   InvalidResponse;
	 
	        private static Map<String, ErrorCode> errorsMap = new HashMap<String, ErrorCode>(4);
	 
	        static {
	            errorsMap.put("missing-input-secret",   MissingSecret);
	            errorsMap.put("invalid-input-secret",   InvalidSecret);
	            errorsMap.put("missing-input-response", MissingResponse);
	            errorsMap.put("invalid-input-response", InvalidResponse);
	        }
	 
	        @JsonCreator
	        public static ErrorCode forValue(String value) {
	            return errorsMap.get(value.toLowerCase());
	        }
	    }

		public boolean isSuccess() {
			return success;
		}

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

		public String getChallengeTs() {
			return challengeTs;
		}

		public void setChallengeTs(String challengeTs) {
			this.challengeTs = challengeTs;
		}

		public String getHostname() {
			return hostname;
		}

		public void setHostname(String hostname) {
			this.hostname = hostname;
		}

		public ErrorCode[] getErrorCodes() {
			return errorCodes;
		}

		public void setErrorCodes(ErrorCode[] errorCodes) {
			this.errorCodes = errorCodes;
		}
	     
}

Powyższe fragmenty kodu są też zawarte w projekcie Clinic (clinic-server, clinic-client) na GitHub >>tutaj<<