Warm tip: This article is reproduced from serverfault.com, please click

c#-ASP.NET Core 2.1 App Engine中没有HTTP / HTTPS重定向

(c# - ASP.NET Core 2.1 no HTTP/HTTPS redirection in App Engine)

发布于 2018-10-23 16:51:23

问题

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

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

不安全的连接

我还在Log Viewer中收到一个错误,警告Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware抛出失败,无法确定重定向的https端口。

在此处输入图片说明

我遵循了MSDN上的文档,仅使它在本地运行,但未在将应用发布到App Engine时使用。 https://docs.microsoft.com/zh-cn/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. AddHttpsRedirection中间件添加到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/zh-cn/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
Questioner
Natthapol Vanasrivilai
Viewed
11
Natthapol Vanasrivilai 2018-10-24 14:36:24

根据MicrosoftApp Engine文档上的提示,创建自己的中间件以查找“ X-Forwarded-Proto ”标头后,以某种方式使它起作用

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

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

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