ASP.NET、NetCoreAPI整合reCAPTCHA V2記錄 1. Google 服務申請與設定 1.1. 註冊新網站 輸入以下網址,會看到下圖的結果:
1 https://www.google.com/recaptcha/admin
1.2. 產生金鑰 點選提交
按鈕後,會跳轉到下圖的頁面,其中有兩個金鑰後續會使用
1.3. 重新進入admin介面 1 https://www.google.com/recaptcha/admin
可以看到已成功建立,並於首頁出現相關面版資訊,如下圖:
Visual Studio 2022
ASP.NET WebForm
找出此軟體進行安裝,如下:
開啟軟體後,勾選紅框選項進行安裝,如下:
建立新專案
第二步驟安裝完成後,建立新專案就會看到新的選項囉,如下:
2.2. 時序圖 簡單來說,大致粗分為:
渲染出reCAPTCHA圖形驗證於client 端 browser
WebServer與Google進行溝通驗證
回傳驗證結果至client端
圖片參考來源來自dejanstojanovic.net
2.3. 程式實作範例 這隻程式的重點在兩個部分:
1 <script src="https://www.google.com/recaptcha/api.js" async defer></script>
1 <div class ="g-recaptcha" data-sitekey ="6L...EA" > </div >
WebForm.aspx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm.aspx.cs" Inherits="ASP_NET_reCAPTCHA.WebForm" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server" > <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="https://www.google.com/recaptcha/api.js" async defer></script> </head> <body> <form id="form1" runat="server" > <div> 帳號:<asp:TextBox ID="TextBox1" runat="server" ></asp:TextBox> 密碼:<asp:TextBox ID="TextBox2" runat="server" ></asp:TextBox> <div class ="g-recaptcha" data-sitekey="6L...EA" ></div> <asp:Button ID="btnSubmit" runat="server" Text="送出" OnClick="btnSubmit_Click" /> <asp:Label ID="lblMsg" runat="server" Text="" ></asp:Label> </div> </form> </body> </html>
當點擊送出
按鈕後,會跑到btnSubmit_Click
事件,接著讓server與google進行驗證確認,重點有幾項:
apiKey
g-recaptcha-response
1 var gRecaptchaResponse = Request.Form["g-recaptcha-response" ];
WebForm.aspx.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 using Newtonsoft.Json;using Newtonsoft.Json.Linq;using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Services.Description;using System.Web.UI;using System.Web.UI.WebControls;using System.Xml.Linq;namespace ASP_NET_reCAPTCHA { public partial class WebForm : System.Web.UI.Page { protected void Page_Load (object sender, EventArgs e ) { } protected void btnSubmit_Click (object sender, EventArgs e ) { var apiKey = "6L...Dh" ; var url = "https://www.google.com/recaptcha/api/siteverify" ; var wc = new System.Net.WebClient(); wc.Headers.Add("Content-Type" , "application/x-www-form-urlencoded" ); var gRecaptchaResponse = Request.Form["g-recaptcha-response" ]; var data = "secret=" + apiKey + "&response=" + gRecaptchaResponse; var json = wc.UploadString(url, data); var success = JsonConvert.DeserializeObject<JObject>(json).Value<bool >("success" ); if (!success) { lblMsg.Text = "驗證碼有誤" ; return ; } lblMsg.Text = "確認過眼神,你不是機器人,但程式還沒完成" ; } } }
2.3.3. 測試與觀查 2.3.3.1. 第一次載入畫面
2.3.3.2. 觀查點選我不是機器人
核取方塊 點選前與後,在document.getElementById("g-recaptcha-response").value
值的變化,如下圖紅框:
2.3.3.3. 最後結果
3. .NET CORE API 程式開發環境說明
3.1. VS2022 NET CORE API 環境建置 key api
找到對應專案類型,如下:
3.2. 程式實作範例 3.2.1. 前端程式碼 準備三個檔案index.html
、script.js
、style.css
,最後結果如下圖:
3.2.2. wwwroot\index.html
跟webform一樣,需要g-recaptcha
與引入https://www.google.com/recaptcha/api.js
。差別是送出的click透過ajax實現驗證。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE html > <head > <title > Login Page</title > <link rel ="stylesheet" href ="style.css" > <script type ="text/javascript" src ="https://www.google.com/recaptcha/api.js" > </script > <script src ="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js" > </script > <script src ="script.js" > </script > </head > <body > <div class ="login-page" > <div class ="form" > <div class ="login-form" > <input type ="text" placeholder ="Username" /> <input type ="password" placeholder ="Password" /> <div class ="g-recaptcha" data-sitekey ="6Lc...EA" > </div > <br > <button onclick ="LoginButton()" > Login</button > </div > </div > </div > </body > </html >
3.2.3. wwwroot\script.js
透過ajax方式call User/Captcha
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function LoginButton ( ) { const reCaptchaResponse = grecaptcha.getResponse (); if (reCaptchaResponse) { $.ajax ({ type : "GET" , url : "https://localhost:7166/api/User/Captcha" , data : { userResponse : reCaptchaResponse }, success : function (data ) { if (data) { alert ("Captcha Verified" ); } else { alert ("Please verify captcha again" ); } }, error : function (error ) { alert ("Please try again" ); } }); } else { alert ("Something went wrong with reCaptcha. Please try again!" ); } }
3.2.4. wwwroot\style.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 @import url(https ://fonts.googleapis.com/css?family=Roboto :300 );.login-page { width : 360px ; padding : 8% 0 0 ; margin : auto; } .form { position : relative; z-index : 1 ; background : rgb (116 , 223 , 187 ); max-width : 360px ; margin : 0 auto 100px ; padding : 30px ; text-align : center; box-shadow : 0 0 20px 0 rgba (0 , 0 , 0 , 0.2 ), 0 5px 5px 0 rgba (0 , 0 , 0 , 0.24 ); } .form input { font-family : "Roboto" , sans-serif; outline : 0 ; background : #f2f2f2 ; width : 100% ; border : 0 ; margin : 0 0 15px ; padding : 15px ; box-sizing : border-box; font-size : 14px ; } .form button { font-family : "Roboto" , sans-serif; text-transform : uppercase; outline : 0 ; background : rgb (8 , 103 , 116 ); width : 100% ; border : 0 ; padding : 15px ; color : #FFFFFF ; font-size : 14px ; -webkit-transition : all 0.3 ease; transition : all 0.3 ease; cursor : pointer; } .form button :hover , .form button :active , .form button :focus { background : #073b44 ; } .container { position : relative; z-index : 1 ; max-width : 300px ; margin : 0 auto; }
3.2.5. 後端程式碼 3.2.6. appsettings.json
設定reCaptcha
金鑰,api controller 會用到
1 2 3 4 5 6 7 8 9 10 11 12 { "Logging" : { "LogLevel" : { "Default" : "Information" , "Microsoft.AspNetCore" : "Warning" } } , "reCaptcha" : { "SecretKey" : "6L...Dh" } , "AllowedHosts" : "*" }
3.2.7. Program.cs
啟動CORS
功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 builder.Services.AddCors(options => { options.AddDefaultPolicy( policy => { policy.AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod(); }); }); app.UseCors();
注入httpclient功能
1 2 builder.Services.AddHttpClient();
完整程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 var builder = WebApplication.CreateBuilder(args);builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddCors(options => { options.AddDefaultPolicy( policy => { policy.AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod(); }); }); builder.Services.AddHttpClient(); var app = builder.Build();if (app.Environment.IsDevelopment()){ app.UseSwagger(); app.UseSwaggerUI(); } app.UseDefaultFiles(); app.UseStaticFiles(); app.UseCors(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
3.2.8. Controllers\UserController
在controllers
資料夾底下建立新controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using Newtonsoft.Json;namespace reCaptchaAPI.Controllers { [Route("api/[controller]" ) ] [ApiController ] public class UserController : ControllerBase { private readonly IConfiguration _configuration; private readonly HttpClient _httpClient; public UserController (IConfiguration configuration, HttpClient httpClient ) { _configuration = configuration; _httpClient = httpClient; } [HttpGet("Captcha" ) ] public async Task<bool > GetreCaptchaResponse (string userResponse ) { var reCaptchaSecretKey = _configuration["reCaptcha:SecretKey" ]; if (reCaptchaSecretKey != null && userResponse != null ) { var content = new FormUrlEncodedContent(new Dictionary<string , string > { {"secret" , reCaptchaSecretKey }, {"response" , userResponse } }); var response = await _httpClient.PostAsync("https://www.google.com/recaptcha/api/siteverify" , content); if (response.IsSuccessStatusCode) { var result = await response.Content.ReadFromJsonAsync<reCaptchaResponse>(); return result.Success; } } return false ; } public class reCaptchaResponse { public bool Success { get ; set ; } public string [] ErrorCodes { get ; set ; } } } }
3.3. 測試
4. 參考連結