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

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

问题

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

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

Insecured connection

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

enter image description here

我遵循了 MSDN 的文档,只让它在本地工作,但当应用程序发布到 App Engine 时却没有。 https://learn.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. 将环境变量添加到 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://learn.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

最佳答案

根据 Microsoft 上的提示,我创建了自己的中间件以查找“X-Forwarded-Proto” header 后,我以某种方式使它起作用和 App Engine文档。

Microsoft: Forwarded Headers Middleware must be enabled for an app to process forwarded headers with UseForwardedHeaders.

App Engine: SSL connections are terminated at the load balancer. Traffic from the load balancer is sent to the instance over an encrypted channel, and then forwarded to the application server over HTTP. The X-Forwarded-Proto header lets you understand if the origin request was HTTP or HTTPs.

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

因此在ConfigureServices方法中配置中间件选项

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

然后在Configure 方法中使用它,然后再做其他事情

app.UseForwardedHeaders();

然后编写自定义中间件,读取转发的 header 并重定向到 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

关于c# - ASP.NET Core 2.1 在 App Engine 中没有 HTTP/HTTPS 重定向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52954158/

相关文章:

c# - 为什么处理 StreamReader 会使流不可读?

c# - 是否有用于 Visual C# 2005 的字符串表资源?

google-app-engine - GAE 中数据级别的唯一约束

c# - 将 List<T> 转换为数组(多维)

c# - 意外更改权限

c# - 如何将javascript日期存储到sql server中?

javascript - 使这个 jquery 批量复选框代码更通用

c# - NUnit 测试中属性的 MissingMethodException

python - AppEngine cron(python)中的每一天,每周,每月,每年

python - google appengine 接收电子邮件错误