如何在代码中为跨域请求注入Auth Header以嵌入受API Key保护的外部页面
解决方案
一、C# 后端代理方案(优先选择,无API Key暴露风险)
通过后端作为中间层代理所有iframe请求,由服务器注入API Key并处理307重定向的Cookie逻辑,完全避免前端接触敏感密钥。
实现步骤
- 新增代理API端点
在ASP.NET Core项目中创建控制器,接收前端iframe的所有请求并转发至目标外部站点。 - 首次请求注入API Key
会话内首次请求时,在请求头添加Authorization: Bearer {你的API Key}后发送给外部站点。 - 捕获并保存Auth Cookie
外部站点返回307重定向时,提取Set-Cookie头内容,存储到服务器会话或前端HttpOnly Cookie中。 - 后续请求自动携带Cookie
同一会话的后续请求,代理直接将存储的Auth Cookie添加到请求头,无需重复注入API Key。 - 转发响应至前端
将外部站点的响应(状态码、headers、内容)原样返回,同时配置CORS允许前端域名访问代理端点。
核心代码示例(ASP.NET Core)
[ApiController] [Route("proxy/{**path}")] public class ProxyController : ControllerBase { private readonly HttpClient _httpClient; private readonly IHttpContextAccessor _httpContextAccessor; public ProxyController(HttpClient httpClient, IHttpContextAccessor httpContextAccessor) { _httpClient = httpClient; _httpContextAccessor = httpContextAccessor; } [AcceptVerbs("GET", "POST", "PUT", "DELETE")] public async Task<IActionResult> ProxyRequest(string path) { var targetUrl = $"https://客户外部网站域名/{path}"; var requestMessage = new HttpRequestMessage(new HttpMethod(Request.Method), targetUrl); // 复制前端请求头(排除敏感项) foreach (var header in Request.Headers) { if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && !requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) ?? false) { // 忽略添加失败的非必要头 } } // 处理认证逻辑 var authCookie = _httpContextAccessor.HttpContext.Session.GetString("ExternalAuthCookie"); if (string.IsNullOrEmpty(authCookie)) { requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "你的API Key"); } else { requestMessage.Headers.Add("Cookie", authCookie); } // 发送请求并获取响应 var response = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead); // 捕获307重定向的Cookie if (response.StatusCode == HttpStatusCode.TemporaryRedirect) { if (response.Headers.TryGetValues("Set-Cookie", out var setCookies)) { var cookieString = string.Join("; ", setCookies); _httpContextAccessor.HttpContext.Session.SetString("ExternalAuthCookie", cookieString); // 同步到前端HttpOnly Cookie,持久化会话 Response.Cookies.Append("ExternalAuthCookie", cookieString, new CookieOptions { HttpOnly = true, Secure = true }); } } // 转发响应头 foreach (var header in response.Headers) { Response.Headers.TryAdd(header.Key, header.Value.ToArray()); } foreach (var header in response.Content.Headers) { Response.Headers.TryAdd(header.Key, header.Value.ToArray()); } // 转发响应内容 var content = await response.Content.ReadAsByteArrayAsync(); return File(content, response.Content.Headers.ContentType?.ToString()); } }
注意事项
- 配置
HttpClient的超时和重定向策略,避免循环重定向。 - 启用服务器会话(如内存会话或分布式缓存),确保Cookie在会话周期内有效。
- 配置CORS规则,允许你的前端域名访问
/proxy路径。 - iframe的
src直接指向代理端点,例如/proxy/目标页面路径。
二、JavaScript前端方案(存在API Key暴露风险)
仅适用于非高敏感场景,API Key会暴露在前端代码中,可能被浏览器开发者工具捕获。
实现思路:同源中间页 + Service Worker
- 创建同源中间页
在你的域名下创建空白页面(如iframe-proxy.html),负责加载外部站点内容并注册Service Worker。 - Service Worker拦截请求
注册Service Worker拦截所有指向外部站点的请求,首次请求注入API Key,后续请求携带缓存的Auth Cookie。 - 处理307重定向Cookie
拦截307响应并提取Cookie,存储到CacheStorage中,供后续请求使用。
核心代码示例
中间页(iframe-proxy.html)
<!DOCTYPE html> <html> <head> <script> if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw-proxy.js') .then(() => console.log('Service Worker 注册成功')) .catch(err => console.error('Service Worker 注册失败', err)); } window.addEventListener('load', () => { fetch('https://客户外部网站域名/目标页面') .then(res => res.text()) .then(html => { document.body.innerHTML = html; // 修正页面内相对资源路径 document.querySelectorAll('script[src], link[href], img[src]').forEach(el => { const attr = el.tagName === 'SCRIPT' || el.tagName === 'IMG' ? 'src' : 'href'; if (el[attr] && !el[attr].startsWith('http')) { el[attr] = `https://客户外部网站域名/${el[attr]}`; } }); }); }); </script> </head> <body></body> </html>
Service Worker(sw-proxy.js)
let authCookie = null; self.addEventListener('fetch', event => { const requestUrl = new URL(event.request.url); if (requestUrl.hostname !== '客户外部网站域名') return; let modifiedRequest = event.request; const headers = new Headers(event.request.headers); if (!authCookie) { // 首次请求注入API Key headers.append('Authorization', 'Bearer 你的API Key'); modifiedRequest = new Request(event.request, { headers }); } else { // 后续请求携带Cookie headers.append('Cookie', authCookie); modifiedRequest = new Request(event.request, { headers }); } event.respondWith( fetch(modifiedRequest) .then(response => { // 捕获307重定向的Cookie if (response.status === 307) { const setCookie = response.headers.get('Set-Cookie'); if (setCookie) authCookie = setCookie.split(';')[0]; } return response; }) .catch(err => console.error('代理请求失败', err)) ); });
注意事项
- Service Worker必须部署在你的同源域名下,受浏览器同源策略限制。
- API Key直接写入前端代码,存在泄露风险,不建议用于高安全要求场景。
- 需处理页面内的相对资源路径,确保所有请求都被Service Worker拦截。
内容的提问来源于stack exchange,提问作者Nathanael de wet
相关产品推荐
相关产品推荐

