進在開發公司的文件中心組件,提供各個子系統的附件上傳下載、預覽、版本更新等功能,前端在今天突然給我發一張圖,說預覽縮略圖遇到問題了,然后發了個截圖給我:
這很明顯是一個跨域問題,
X-Frame-Options HTTP 響應頭是用來給瀏覽器指示允許一個頁面可否在 <frame>, <iframe>或者 <object> 中展現的標記。網站可以使用此功能,來確保自己網站的內容沒有被嵌到別人的網站中去,也從而避免了點擊劫持 (clickjacking) 的攻擊。
X-Frame-Options 有三個值:
DENY 表示該頁面不允許在 frame 中展示,即便是在相同域名的頁面中嵌套也不允許。 SAMEORIGIN 表示該頁面可以在相同域名頁面的 frame 中展示(一般默認是這種)。 ALLOW-FROM uri 表示該頁面可以在指定來源的 frame 中展示。
此處很明顯需要在中間件里面修改一下響應頭的X-Frame-Options屬性,core的中間件流程如下:
所以我們需要實現一個響應頭的增刪集合類:
/// <summary> /// 響應頭的增刪集合 /// </summary> public class SecurityHeadersPolicy { public IDictionary<string, string> SetHeaders { get; } = new Dictionary<string, string>(); public ISet<string> RemoveHeaders { get; } = new HashSet<string>(); }
然后實現一個增刪響應頭的中間件:
/// <summary> /// 中間件實現 /// </summary> public class SecurityHeadersMiddleware { private readonly RequestDelegate _next; private readonly SecurityHeadersPolicy _policy; public SecurityHeadersMiddleware(RequestDelegate next, SecurityHeadersPolicy policy) { _next = next; _policy = policy; } public async Task Invoke(HttpContext context) { IHeaderDictionary headers = context.Response.Headers; foreach (var headerValuePair in _policy.SetHeaders) { headers[headerValuePair.Key] = headerValuePair.Value; } foreach (var header in _policy.RemoveHeaders) { headers.Remove(header); } await _next(context); } }
提供響應頭的增刪方法:
/// <summary> /// 響應頭的增刪方法 /// </summary> public class SecurityHeadersBuilder { private readonly SecurityHeadersPolicy _policy = new SecurityHeadersPolicy(); public SecurityHeadersBuilder AddCustomHeader(string header, string value) { _policy.SetHeaders[header] = value; return this; } public SecurityHeadersBuilder RemoveHeader(string header) { _policy.RemoveHeaders.Add(header); return this; } public SecurityHeadersPolicy Build() { return _policy; } }
然后我們需要一個中間件的拓展方法:
/// <summary> /// 中間件拓展方法 /// </summary> public static class UseSecurityHeaders { public static IApplicationBuilder UseSecurityHeadersMiddleware(this IApplicationBuilder app, SecurityHeadersBuilder builder) { SecurityHeadersPolicy policy = builder.Build(); return app.UseMiddleware<SecurityHeadersMiddleware>(policy); } }
然后就是在startup的Configure方法中注冊我們的中間件:
//允許iframe嵌入資源 app.UseSecurityHeadersMiddleware(new SecurityHeadersBuilder() .AddCustomHeader("X-Frame-Options", "AllowAll") );
我在這里使用的值是“AllowAll” 而不是“ALLOW-FROM uri” 是為了方便測試,如果開發的話應該是需要進行配置的,到這里再嵌入網頁即可成功。