前言
最近公司計畫導入 reCAPTCHA Enterprise,本篇文章 記錄一下實作細節
設定 reCAPTCHA Enterprise
啟用服務
gcloud services enable recaptchaenterprise.googleapis.com
建立 service account
GCP 官方文件 - Set up reCAPTCHA Enterprise on Google Cloud
# 建立 service-accounts
gcloud iam service-accounts create $Name
# 綁定權限
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:$Name@$PROJECT_ID.iam.gserviceaccount.com" --role="roles/recaptchaenterprise.agent"
# 下載.json檔憑證至本地端
# 若服務是在GCP上且機器環境的服務帳戶 含有 recaptchaenterprise.assessments.create權限,則可略過 不需憑證
gcloud iam service-accounts keys create $KEY_PATH --iam-account=$NAME@$PROJECT_ID.iam.gserviceaccount.com
ex:
gcloud iam service-accounts create recaptcha-account
gcloud projects add-iam-policy-binding xxx --member="serviceAccount:recaptcha-account@xxx.iam.gserviceaccount.com" --role="roles/recaptchaenterprise.agent"
gcloud iam service-accounts keys create D:\Lab\service-account-file.json --iam-account=recaptcha-account@xxx.iam.gserviceaccount.com
- 建立 reCAPTCHA Enterprise sitekey
GCP 官方文件 - Creating a site key
gcloud recaptcha keys create \
--web \
--display-name=[DISPLAY_NAME] \
--integration-type=[INTEGRATION_TYPE] \
--domains=[DOMAINS]
ex:
# 直接取token 驗證分數
gcloud recaptcha keys create \
--web \
--display-name=leo-score \
--integration-type=SCORE \
--domains=localhost
# 透過 checkbox 取token 驗證分數
gcloud recaptcha keys create \
--web \
--display-name=leo-checkbox \
--integration-type=CHECKBOX \
--domains=localhost
設定成功後 目前有兩筆 recaptcha enterprise 金鑰
建立 .Net Core 3.1 專案
dotnet new sln -o reCAPTCHA_Enterprise_Sample
dotnet new mvc -f netcoreapp3.1 -o reCAPTCHA_Enterprise_Sample
dotnet sln reCAPTCHA_Enterprise_Sample/reCAPTCHA_Enterprise_Sample.sln add reCAPTCHA_Enterprise_Sample/reCAPTCHA_Enterprise_Sample.csproj
安裝套件
dotnet add package Google.Cloud.RecaptchaEnterprise.V1
程式實作
呼叫 Google API時,有分在 GCP 的機器環境 跟 地端環境
若服務是跑在GCP的機器環境,需確認機器環境的服務帳戶 含有 recaptchaenterprise.assessments.create 權限 則可以直接呼叫 不需憑證
若服務是在地端環境 或非 GCP 機器環境,則需要將憑證下載至機器上,呼叫時在設定憑證路徑
程式碼可參考 w4560000/reCAPTCHA_Enterprise_Sample
- 新增 CreateAssessmentSample.cs
程式碼 參考 GCP 官方文件 - Create an assessment 做微調
using Google.Api.Gax.ResourceNames;
using Google.Cloud.RecaptchaEnterprise.V1;
namespace reCAPTCHA_Enterprise_Sample.Service
{
public class CreateAssessmentSample
{
public RecaptchaEnterpriseServiceClient GetRecaptchaEnterpriseServiceClient_SetEnv()
{
System.Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", @"D:\Lab\reCAPTCHA_Enterprise_Sample\service-account-file.json");
return RecaptchaEnterpriseServiceClient.Create();
}
public RecaptchaEnterpriseServiceClient GetRecaptchaEnterpriseServiceClient_SetCredentialsPath()
{
return new RecaptchaEnterpriseServiceClientBuilder()
{
CredentialsPath = @"D:\Lab\reCAPTCHA_Enterprise_Sample\service-account-file.json"
}.Build();
}
// Create an assessment to analyze the risk of an UI action.
// projectID: GCloud Project ID.
// recaptchaSiteKey: Site key obtained by registering a domain/app to use recaptcha.
// token: The token obtained from the client on passing the recaptchaSiteKey.
// recaptchaAction: Action name corresponding to the token.
public decimal createAssessment(string projectID = "project-id", string recaptchaSiteKey = "recaptcha-site-key",
string token = "action-token", string recaptchaAction = "action-name")
{
// Create the client.
// TODO: To avoid memory issues, move this client generation outside
// of this example, and cache it (recommended) or call client.close()
// before exiting this method.
// 若在GCP 機器環境的服務帳戶 含有 recaptchaenterprise.assessments.create 權限 則可以直接呼叫 不需憑證
RecaptchaEnterpriseServiceClient client = RecaptchaEnterpriseServiceClient.Create();
// 若在地端環境 或 非 GCP 機器環境,則可以將憑證下載至機器上,呼叫時在設定憑證路徑
//RecaptchaEnterpriseServiceClient client = GetRecaptchaEnterpriseServiceClient_SetEnv(); // 透過環境變數
//RecaptchaEnterpriseServiceClient client = GetRecaptchaEnterpriseServiceClient_SetCredentialsPath(); // 設定 CredentialsPath
ProjectName projectName = new ProjectName(projectID);
// Build the assessment request.
CreateAssessmentRequest createAssessmentRequest = new CreateAssessmentRequest()
{
Assessment = new Assessment()
{
// Set the properties of the event to be tracked.
Event = new Event()
{
SiteKey = recaptchaSiteKey,
Token = token,
ExpectedAction = recaptchaAction
},
},
ParentAsProjectName = projectName
};
Assessment response = client.CreateAssessment(createAssessmentRequest);
// Check if the token is valid.
if (response.TokenProperties.Valid == false)
{
System.Console.WriteLine("The CreateAssessment call failed because the token was: " +
response.TokenProperties.InvalidReason.ToString());
return 0;
}
// Check if the expected action was executed.
if (response.TokenProperties.Action != recaptchaAction)
{
System.Console.WriteLine("The action attribute in reCAPTCHA tag is: " +
response.TokenProperties.Action.ToString());
System.Console.WriteLine("The action attribute in the reCAPTCHA tag does not " +
"match the action you are expecting to score");
return 0;
}
// Get the risk score and the reason(s).
// For more information on interpreting the assessment,
// see: https://cloud.google.com/recaptcha-enterprise/docs/interpret-assessment
System.Console.WriteLine("The reCAPTCHA score is: " + ((decimal)response.RiskAnalysis.Score));
foreach (RiskAnalysis.Types.ClassificationReason reason in response.RiskAnalysis.Reasons)
{
System.Console.WriteLine(reason.ToString());
}
return (decimal)response.RiskAnalysis.Score;
}
}
}
- 修改 HomeController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using reCAPTCHA_Enterprise_Sample.Models;
using reCAPTCHA_Enterprise_Sample.Service;
using System;
using System.Diagnostics;
namespace reCAPTCHA_Enterprise_Sample.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
TempData["sitekey"] = "6Ld_Os8fAAAAACNQDEOxHKvxBWmN2wK6_GUXAZ08";
TempData["recaptchaAction"] = "Verify_CheckBox";
return View();
}
public IActionResult Privacy()
{
TempData["sitekey"] = "6LeUx88fAAAAAHsA_b3jPKRVg8Yyyua5Ub2qjE8I";
TempData["recaptchaAction"] = "Verify_GetToken";
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
[HttpGet]
public string CreateAssessment(string token, string recaptchaSiteKey, string recaptchaAction)
{
try
{
// 注意 需自行替換projectID
return new CreateAssessmentSample().createAssessment(
projectID: "xxx",
recaptchaSiteKey: recaptchaSiteKey,
token: token,
recaptchaAction: recaptchaAction).ToString();
}
catch (Exception ex)
{
return ex.Message;
}
}
}
}
- 修改 Index.cshtml
@{
ViewBag.Title = "Home Page";
}
<head>
<script src="https://www.google.com/recaptcha/enterprise.js"></script>
</head>
<body>
<div class="g-recaptcha"
data-sitekey="@TempData["sitekey"]"
data-action='@TempData["recaptchaAction"]'
data-callback='test_recaptcha'>
</div>
</body>
<script>
function test_recaptcha(token) {
$.get(`/Home/CreateAssessment?token=${token}&recaptchaSiteKey=@TempData["sitekey"]&recaptchaAction=@TempData["recaptchaAction"]`)
.then((res) => alert(res));
}
</script>
- 修改 Privacy.cshtml
@{ ViewBag.Title = "Home Page"; } @*<style> .grecaptcha-badge { visibility: hidden; } </style>*@ <head> <script src="https://www.google.com/recaptcha/enterprise.js?render=@TempData["sitekey"]"></script> </head> <body> <input type="button" class="btn btn-secondary col-sm-2" id="test_verify_score" value="verify_score" onclick="verify_score_click()"> </body> <script> function verify_score_click() { grecaptcha.enterprise.ready(function () { grecaptcha.enterprise.execute('@TempData["sitekey"]', { action: '@TempData["recaptchaAction"]' }).then(function (token) { $.get(`/Home/CreateAssessment?token=${token}&recaptchaSiteKey=@TempData["sitekey"]&recaptchaAction=@TempData["recaptchaAction"]`) .then((res) => alert(res)); }); }); } </script>
測試結果
測試 Checkbox
/Home/Index測試 Score
/Home/Privacy
補充
若網站右下角 有出現 reCAPTCHA的隱私權說明
可參考 recaptcha 官網 faq 處理方式
轉載請註明來源,若有任何錯誤或表達不清楚的地方,歡迎在下方評論區留言,也可以來信至 leozheng0621@gmail.com
如果文章對您有幫助,歡迎斗內(donate),請我喝杯咖啡