Abp vNext 番外篇-疑難雜症丨nginx反向代理-部署
緣起
說明:名字用Abp vNext是因為這屬於我Abp vNext系列的文章,該問題其實應該屬於ids4的部署問題和abp沒啥關係。
問題源於週五晚上在和群友聊的時候聊到使用Nginx反向代理後端來做SSL,本來覺得這個問題很簡單我就直接部署了一個沒想到這就碰到問題了,我的ids4
的issuer出問題了。
大家可以看下面這幅圖,我的Scheme分明是Https但是到了issuer卻變成了http。
下面是我的nginx,我把scheme
和X-Forwarded-For
都做了配置,但是後端還是拿不到正確的scheme
。
初步方案
我之前我仔細閱讀過老張的ids4系列,我記得他講過這方面的東西,然後我就去翻閱了他的部落格,通過手動修改IssuerUri
研究文件
我在官方文件看到了這麼一句話(建議不要設定此屬性,該屬性根據主機名推斷頒發者名稱),我又加以想想發現這樣寫會存在一個問題,如果我的專案像被多個域名對映豈不是直接歇菜了(當然這個是可以配置的,但是我的想法是約定大於配置,儘量不要去更改這些東西)。
查詢根源
我決定自己從源頭來看看到底什麼原因,我在IdentityServer4
的原始碼中找到了下面程式碼,在此我們知道了為啥設定IssuerUri
會生效,另外我們也看到GetIdentityServerOrigin
中的Http來自於context.Request.Scheme
;
/// <summary> /// Gets the identity server issuer URI. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException">context</exception> public static string GetIdentityServerIssuerUri(this HttpContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); // if they've explicitly configured a URI then use it, // otherwise dynamically calculate it var options = context.RequestServices.GetRequiredService<IdentityServerOptions>(); var uri = options.IssuerUri; if (uri.IsMissing()) { uri = context.GetIdentityServerOrigin() + context.GetIdentityServerBasePath(); if (uri.EndsWith("/")) uri = uri.Substring(0, uri.Length - 1); if (options.LowerCaseIssuerUri) { uri = uri.ToLowerInvariant(); } } return uri; } public static string GetIdentityServerOrigin(this HttpContext context) { var options = context.RequestServices.GetRequiredService<IdentityServerOptions>(); var request = context.Request; if (options.MutualTls.Enabled && options.MutualTls.DomainName.IsPresent()) { if (!options.MutualTls.DomainName.Contains(".")) { if (request.Host.Value.StartsWith(options.MutualTls.DomainName, StringComparison.OrdinalIgnoreCase)) { return request.Scheme + "://" + request.Host.Value.Substring(options.MutualTls.DomainName.Length + 1); } } } return request.Scheme + "://" + request.Host.Value; } /// <summary> /// Gets the base path of IdentityServer. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> public static string GetIdentityServerBasePath(this HttpContext context) { return context.Items[Constants.EnvironmentKeys.IdentityServerBasePath] as string; }
尋找方案
我在部落格園找到了LouieGuo
的一篇文章,他給出了一個官方issues:https://github.com/dotnet/AspNetCore.Docs/issues/2384
其實主要問題就在於proxy_pass http://172.17.0.8:8000;
我們請求會被轉發,這裡就變成了http請求了,導致context.Request.Scheme
拿到的就是http,解決方案是配置雙方(nginx/kestrel)的 X-Forwarded-Proto 讓其正確地識別實際使用者發出的協議是 http 還是 https。
程式碼
在 OnApplicationInitialization
方法中加入
var forwardOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
};
forwardOptions.KnownNetworks.Clear();
forwardOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardOptions);
反思
這是目前我的一個解決方案,這個方案說實話不是很好,因為對程式碼有汙染,希望大佬如果有更好的方案給我留言蟹蟹!
也歡迎大家閱讀我的Abp vNext系列教程
聯絡作者:加群:867095512 @MrChuJiu