【问题标题】:ASP.NET Core 2.1 no HTTP/HTTPS redirection in App EngineASP.NET Core 2.1 在 App Engine 中没有 HTTP/HTTPS 重定向
【发布时间】:2019-03-27 23:50:14
【问题描述】:

问题

当应用发布到 App Engine 时,我无法让从 HTTP 到 HTTPS 的自动重定向正常工作。

当我通过 example.com 访问该网站时,该网站被路由到 http://www.example.com 并显示连接不安全。 当我通过https://www.example.com 访问该网站时,该网站将使用谷歌管理的 SSL 正确保护。但是不会发生从 HTTP 到 HTTPS 的自动重定向。

我还在日志查看器中收到错误警告,提示 Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware 正在抛出无法确定重定向的 https 端口。

我已按照 MSDN 的文档进行操作,仅在本地运行,但在应用发布到 App Engine 时无法运行。 https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-2.1&tabs=visual-studio

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory logger)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseStatusCodePages();
        app.UseExceptionHandler("/Error");
        app.UseHsts(); // This was added by the template
    }

    app.UseHttpsRedirection(); // This was added by the template
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseAuthentication();
    app.UseMvc();
}

这是 Program.cs。基本上来自项目模板的默认值

public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
    return WebHost.CreateDefaultBuilder(args)
        .CaptureStartupErrors(true)
        .UseStartup<Startup>();
}

用于部署的 app.yaml

runtime: aspnetcore
env: flexible
automatic_scaling:
  min_num_instances: 1
  max_num_instances: 20
  cpu_utilization:
    target_utilization: 0.8
readiness_check:
  path: "/readinesscheck"
  check_interval_sec: 5
  timeout_sec: 4
  failure_threshold: 2
  success_threshold: 2
  app_start_timeout_sec: 300
liveness_check:
  path: "/livenesscheck"
  check_interval_sec: 30
  timeout_sec: 4
  failure_threshold: 2
  success_threshold: 2
skip_files:
  - node_modules/
  - wwwroot/src/vendor/
  - ^(.*/)?.*\.pdb$
  - ^(.*/)?.*\.log$

我尝试过的是以下(一次只有一个)

  1. 将HttpsRedirection 中间件添加到ConfigureServices 方法。

最终导致应用程序无法访问(502 服务器错误)。

services.AddHttpsRedirection(options =>
{
    options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
    options.HttpsPort = 443;
});
  1. 将 EnvironmentVariable 添加到 app.yaml

还导致应用无法访问(502 服务器错误)。

env_variables:
   ASPNETCORE_HTTPS_PORT: "443"
  1. 在 Program.cs 中手动配置 HTTPS 端口

还导致应用无法访问(502 服务器错误)。

WebHost.CreateDefaultBuilder(args)
    .UseSetting("https_port", "8080") // also return 502 when port is 443
  1. 在 ConfigureServices 方法中配置 ForwardedHeaderOptions,在 Configure 方法中使用 ForwardedHeaderOptions。 https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1#other-proxy-server-and-load-balancer-scenarios

应用程序可以访问,但没有自动 HTTP/HTTPS 重定向。

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = 
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

app.UseForwardedHeaders();
  1. 在 Dockerfile 中手动公开 443 和 8080 端口。

应用程序可以访问,但没有自动 HTTP/HTTPS 重定向。我了解当 app.yaml 中的运行时设置为 aspnetcore 时。发布过程自动生成自己的 Dockerfile,用于将应用部署到 App Engine。

EXPOSE 443
EXPOSE 8080

【问题讨论】:

    标签: c# asp.net google-app-engine asp.net-core google-cloud-platform


    【解决方案1】:

    根据MicrosoftApp Engine 文档上的提示,我创建了自己的中间件以查找“X-Forwarded-Proto”标头后,不知何故我得到了这个工作。

    Microsoft:必须启用转发标头中间件,应用才能使用 UseForwardedHeaders 处理转发标头。

    App Engine: SSL 连接在负载平衡器处终止。来自负载均衡器的流量通过加密通道发送到实例,然后通过 HTTP 转发到应用程序服务器。 X-Forwarded-Proto 标头可让您了解原始请求是 HTTP 还是 HTTPs。

    Microsoft 要求在应用开始处理转发的标头之前先激活中间件

    所以在ConfigureServices方法中配置中间件选项

    services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = 
            ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    });
    

    并在 Configure 方法中使用它,然后再使用它

    app.UseForwardedHeaders();
    

    然后编写自定义中间件,读取转发的标头并重定向到 HTTPS,包括查询。

    配置方法中

    app.Use(async (context, next) =>
    {
        if (context.Request.IsHttps || context.Request.Headers["X-Forwarded-Proto"] == Uri.UriSchemeHttps)
        {
            await next();
        }
        else
        {
            string queryString = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : string.Empty;
            var https = "https://" + context.Request.Host + context.Request.Path + queryString;
            context.Response.Redirect(https);
        }
    });
    

    最后 Configure 方法看起来像这样

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseForwardedHeaders();
        app.Use(async (context, next) =>
        {
            if (context.Request.IsHttps || context.Request.Headers["X-Forwarded-Proto"] == Uri.UriSchemeHttps)
            {
                await next();
            }
            else
            {
                string queryString = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : string.Empty;
                var https = "https://" + context.Request.Host + context.Request.Path + queryString;
                context.Response.Redirect(https);
            }
        });
    
        if (env.IsDevelopment())
        {
            // code removed for clarity
        }
        else
        {
            // code removed for clarity
            app.UseHsts();
        }
    
        app.UseHttpsRedirection();
        // code removed for clarity
        app.UseMvc();
    }
    

    现在导航到example.com 直接重定向我https://www.example.com

    【讨论】:

    • 这是一个很好的答案,它对我有用。我想补充一点,您应该使用 context.Response.Redirect(https, true) 而不是 context.Response.Redirect(https),因为前者将使用 HTTP 状态代码 301 而不是 302 进行重定向。Google 建议为此使用 301:support.google.com/webmasters/answer/6073543
    • 非常感谢您!我一直在与这个作斗争。仍然有点恼火,听起来这里的说明docs.microsoft.com/en-us/aspnet/core/host-and-deploy/… 应该涵盖这个用例而不需要自定义重定向。
    【解决方案2】:

    这对我有用(代码位于 Startup.cs):

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<ForwardedHeadersOptions>(options =>
        {
            options.ForwardedHeaders = 
                ForwardedHeaders.XForwardedFor | 
                ForwardedHeaders.XForwardedProto;
    
            options.KnownNetworks.Clear();
            options.KnownProxies.Clear();
        });
    
        services.AddHttpsRedirection(opt => opt.HttpsPort = 443);
    
        // code removed for clarity
    }
    
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            // code removed for clarity
        }
        else
        {
            // code removed for clarity
            app.UseHsts();
        }
    
        app.UseForwardedHeaders();
        app.UseHttpsRedirection();
        
        // code removed for clarity
    }
            
    

    【讨论】:

      【解决方案3】:

      在使用任何类型的中间件之前,可以在Startup.Configure中手动设置方案:

      app.Use((context, next) =>
      {
          context.Request.Scheme = "https";
          return next();
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-04
        • 1970-01-01
        • 2017-09-05
        • 1970-01-01
        • 2020-04-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多