Skip to main content
BuildingBlocks.Security.BotProtection, public form ve giriş akışlarını otomatik botlara karşı korumak için Google reCAPTCHA v3 doğrulaması sağlar. v3 görsel bir challenge sunmaz; her isteğe 0.0–1.0 arası bir skor verir. Validator skoru eşikle, beklenen action ile ve (opsiyonel) hostname ile karşılaştırır; uyuşmazlıkta exception fırlatır.

IRecaptchaValidator

MetotİmzaDavranış
ValidateAsyncTask ValidateAsync(string token, string expectedAction, CancellationToken = default)Başarılıysa sessizce döner; başarısızsa RecaptchaValidationException fırlatır
GoogleRecaptchaValidator implementasyonu Google siteverify API’sine secret + response (token) gönderir ve yanıtı sırayla kontrol eder:
public async Task ValidateAsync(string token, string expectedAction, CancellationToken ct = default)
{
    if (string.IsNullOrWhiteSpace(token))
        throw new RecaptchaValidationException("Recaptcha token gerekli.");

    var content = new FormUrlEncodedContent(new Dictionary<string, string>
    {
        ["secret"]   = _options.SecretKey,
        ["response"] = token
    });

    var response = await _httpClient.PostAsync(
        "https://www.google.com/recaptcha/api/siteverify", content, ct);
    var result = JsonSerializer.Deserialize<RecaptchaResponse>(
        await response.Content.ReadAsStringAsync(ct));

    if (result is null || !result.Success)
        throw new RecaptchaValidationException("Recaptcha doğrulaması başarısız oldu.");
    if (result.Score < _options.ScoreThreshold)
        throw new RecaptchaValidationException($"Recaptcha puanı çok düşük: {result.Score}");
    if (!string.Equals(result.Action, expectedAction, StringComparison.Ordinal))
        throw new RecaptchaValidationException("Recaptcha işlemi uyuşmazlığı.");
    if (_options.ValidateHostname &&
        !_options.AllowedHostnames.Contains(result.Hostname, StringComparer.OrdinalIgnoreCase))
        throw new RecaptchaValidationException("Hostname mismatch.");
}
KontrolHata
Token boşRecaptcha token gerekli.
success != trueRecaptcha doğrulaması başarısız oldu.
score < ScoreThresholdRecaptcha puanı çok düşük: {score}
action != expectedActionRecaptcha işlemi uyuşmazlığı.
Hostname allowlist dışıHostname mismatch.

Konfigürasyon — RecaptchaOptions

Recaptcha bölümüne bind edilir.
ÜyeTipVarsayılanAçıklama
Urlstringhttps://www.google.com/recaptcha/api/siteverifyDoğrulama endpoint’i
SecretKeystringreCAPTCHA secret (gizli)
ScoreThresholdfloat0.6Bu skorun altı reddedilir
ValidateHostnamebooltrueHostname kontrolü açık/kapalı
AllowedHostnamesstring[][]İzinli hostname listesi
{
  "Recaptcha": {
    "SecretKey": "6Lc...secret",
    "ScoreThreshold": 0.6,
    "ValidateHostname": true,
    "AllowedHostnames": ["app.example", "www.example"]
  }
}
SiteKey frontend tarafına aittir (token üretimi için) ve backend RecaptchaOptions’ında yer almaz; backend yalnızca SecretKey ile doğrulama yapar.

DI kaydı — AddRecaptcha

Validator, 5 sn timeout’lu ve Polly retry’lı typed HttpClient ile kaydedilir (3 deneme, 200 ms ara):
public static IServiceCollection AddRecaptcha(this IServiceCollection services, IConfiguration configuration)
{
    services.Configure<RecaptchaOptions>(configuration.GetSection("Recaptcha"));

    services.AddHttpClient<IRecaptchaValidator, GoogleRecaptchaValidator>(client =>
        {
            client.Timeout = TimeSpan.FromSeconds(5);
        })
        .AddTransientHttpErrorPolicy(policy =>
            policy.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(200)));

    return services;
}

Kullanım — public komut içinde doğrulama

public class SubmitContactFormCommandHandler(IRecaptchaValidator recaptcha)
    : IRequestHandler<SubmitContactFormCommand, Unit>
{
    public async Task<Unit> Handle(SubmitContactFormCommand request, CancellationToken ct)
    {
        // expectedAction frontend'deki grecaptcha.execute({ action: "contact" }) ile eşleşmeli
        await recaptcha.ValidateAsync(request.RecaptchaToken, expectedAction: "contact", ct);

        // doğrulama geçtiyse iş mantığı...
        return Unit.Value;
    }
}
RecaptchaValidationException ProblemDetails katmanında uygun HTTP yanıtına çevrilir.
Skor eşiğini akışa göre ayarlayın: düşük riskli public formlarda 0.5–0.6, login gibi hassas akışlarda 0.7+. action adını her zaman frontend grecaptcha.execute çağrısıyla birebir aynı tutun.

İlgili

Device Detector

Risk skoru ile birlikte katmanlı bot savunması.

OTP

Challenge durumunda ikinci faktör.

Frontend

React SPA’da reCAPTCHA token üretimi.

Kimlik doğrulama

Public giriş akışlarının korunması.