基于ASP.NET Core 6与原生JS的reCAPTCHA v3校验后加载内容实现
实现方案
你的初步思路完全可行,整体逻辑分为前端交互+reCAPTCHA校验、后端校验+敏感内容返回两部分,通用实现逻辑和示例代码如下:
整体流程
- 前端初始加载时仅渲染公开内容,敏感内容区域留空占位,同时加载reCAPTCHA v3 SDK
- 触发预设的用户交互行为(如点击查看按钮、滚动到指定区域等)后,前端调用reCAPTCHA接口生成行为校验token
- 前端通过原生fetch将token提交到后端校验接口
- 后端携带token、站点密钥调用Google reCAPTCHA服务端校验接口,判断用户评分是否达到预设的人类阈值(通常设为0.5,可按需调整)
- 校验通过则后端读取受保护的敏感文件内容返回,校验失败直接返回错误
- 前端拿到合法内容后插入到预留的DOM节点中展示
前端实现(原生JS,无jQuery)
页面基础结构
<!-- 敏感内容占位容器 --> <div id="sensitive-content-wrap"></div> <!-- 触发加载的交互按钮,可按需替换为其他交互触发逻辑 --> <button id="view-sensitive-btn">查看受限内容</button> <!-- 引入reCAPTCHA v3,替换为你申请的站点sitekey --> <script src="https://www.google.com/recaptcha/api.js?render=你的reCAPTCHA站点KEY"></script>
交互逻辑代码
const viewBtn = document.querySelector('#view-sensitive-btn'); const contentWrap = document.querySelector('#sensitive-content-wrap'); viewBtn.addEventListener('click', async () => { // 生成reCAPTCHA校验token const recaptchaToken = await grecaptcha.execute('你的reCAPTCHA站点KEY', { action: 'access_sensitive_content' }); try { const response = await fetch('/api/SensitiveContent/Get', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token: recaptchaToken }) }); if (response.ok) { // 校验通过,插入内容到DOM const content = await response.text(); contentWrap.innerHTML = content; } else { contentWrap.textContent = '身份校验失败,无法查看受限内容'; } } catch (err) { contentWrap.textContent = '请求异常,请稍后重试'; } });
后端实现(ASP.NET Core 6)
前置配置
在appsettings.json中添加reCAPTCHA配置:
"RecaptchaConfig": { "SecretKey": "你的reCAPTCHA服务端密钥", "VerifyEndpoint": "https://www.google.com/recaptcha/api/siteverify", "PassScore": 0.5 }
在Program.cs中注册HttpClient服务:
builder.Services.AddHttpClient();
接口实现代码
using Microsoft.AspNetCore.Mvc; using System.Net.Http.Json; using System.IO; [ApiController] [Route("api/[controller]")] public class SensitiveContentController : ControllerBase { private readonly IHttpClientFactory _httpClientFactory; private readonly IConfiguration _config; private readonly IWebHostEnvironment _hostEnv; public SensitiveContentController(IHttpClientFactory httpClientFactory, IConfiguration config, IWebHostEnvironment hostEnv) { _httpClientFactory = httpClientFactory; _config = config; _hostEnv = hostEnv; } [HttpPost("Get")] public async Task<IActionResult> GetSensitiveContent([FromBody] VerifyRequest request) { // 调用reCAPTCHA服务端校验接口 var httpClient = _httpClientFactory.CreateClient(); var verifyForm = new Dictionary<string, string> { {"secret", _config["RecaptchaConfig:SecretKey"]}, {"response", request.Token}, {"remoteip", HttpContext.Connection.RemoteIpAddress?.ToString()} }; var verifyResult = await httpClient.PostAsJsonAsync(_config["RecaptchaConfig:VerifyEndpoint"], verifyForm); var verifyData = await verifyResult.Content.ReadFromJsonAsync<RecaptchaVerifyResponse>(); // 校验不通过直接返回403 if (!verifyData.Success || verifyData.Score < double.Parse(_config["RecaptchaConfig:PassScore"])) { return Forbid(); } // 校验通过,读取敏感文件返回 // 注意:敏感文件不要放在wwwroot目录下,避免被直接公开访问 var filePath = Path.Combine(_hostEnv.ContentRootPath, "ProtectedFiles", "sensitive.html"); var content = await System.IO.File.ReadAllTextAsync(filePath); return Content(content, "text/html"); } } // 用到的实体类 public class VerifyRequest { public string Token { get; set; } } public class RecaptchaVerifyResponse { public bool Success { get; set; } public double Score { get; set; } public string Action { get; set; } public DateTime ChallengeTs { get; set; } public string Hostname { get; set; } public string[] ErrorCodes { get; set; } }
注意事项
- 敏感文件必须放在非wwwroot的受保护目录下,避免用户通过静态资源路径直接访问
- 生产环境中reCAPTCHA的密钥不要硬编码,建议使用ASP.NET Core密钥管理器、环境变量或者云配置中心存储
- 可根据业务安全需求调整PassScore阈值,阈值越高校验越严格
内容的提问来源于stack exchange,提问作者Munchkin
相关产品推荐
相关产品推荐

