首页 .Net Abp vNext 番外篇-疑难杂症丨nginx反向代理-部署

Abp vNext 番外篇-疑难杂症丨nginx反向代理-部署

系列文章列表,点击展示/隐藏

系列教程一目录:知识点源码解析

系列教程二目录:Bcvp AbpVnext讲解

系列教程三目录:单个知识点讲解

系列教程四目录:分库分表(日志系统案例讲解)

本文梯子

    正文

    缘起

    说明:名字用Abp vNext是因为这属于我Abp vNext系列的文章,该问题其实应该属于ids4的部署问题和abp没啥关系。

    问题源于周五晚上在和群友聊的时候聊到使用Nginx反向代理后端来做SSL,本来觉得这个问题很简单我就直接部署了一个没想到这就碰到问题了,我的ids4的issuer出问题了。

    大家可以看下面这幅图,我的Scheme分明是Https但是到了issuer却变成了http。

    问题图

    下面是我的nginx,我把schemeX-Forwarded-For都做了配置,但是后端还是拿不到正确的scheme
    Ngxin配置

    初步方案

    我之前我仔细阅读过老张的ids4系列,我记得他讲过这方面的东西,然后我就去翻阅了他的博客,通过手动修改IssuerUri来解决。

    修改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 conpd 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);
    

    解决方案

    解决方案

    反馈

    @喝口开水

    @MrChuJiu nginx反向代理后,实际取得的request.scheme 确实是难以避免的
    
    官方文档虽然说建议不要修改,我认为,还是要结合的你的实际场景。
    
    另外,如果把宿主程序设为https,nginx反向代理到了https的宿主程序。这样虽然可以解决scheme问题,但是额外就是性能损耗
    还要浪费多余的CPU时间去加密、解密、https的握手,也带来了带多的损耗
    
    所以,要么就简单一点,直接改配置
    要么就用你最后的那个forward方案
    

    反思

    这是目前我的一个解决方案,这个方案说实话不是很好,因为对代码有污染,希望大佬如果有更好的方案给我留言蟹蟹!

    也欢迎大家阅读我的Abp vNext系列教程

    联系作者:加群:867095512 @MrChuJiu

    特别声明:本站部分内容收集于互联网是出于更直观传递信息的目的。该内容版权归原作者所有,并不代表本站赞同其观点和对其真实性负责。如该内容涉及任何第三方合法权利,请及时与824310991@qq.com联系,我们会及时反馈并处理完毕。