ASP.NET Core 2.0でアプリケーションがリバースプロキシの後ろにあるケースで、リバースプロキシがHTTPSで受け、アプリにはHTTPで受け渡すような構成というのはよくあるかと思います。
しかしASP.NET Coreは標準のままでは Request.Scheme には”http”が入ることになり、”https”が入っていなくて不都合が…という状況が発生します。
そんな時は大抵のリバースプロキシが送り出すであろう X-Forwarded-* ヘッダーフィールドを反映するミドルウェアがあるのでそれを有効にすることで、リバースプロキシにアクセスされた際の情報を維持できます。
その機能を有効にするには UseForwardedHeaders メソッドでミドルウェアを使用するようにし、その際にどのヘッダーフィールドを使うかを指定します。次の例は上位サーバーからのリクエストの X-Forwareded-Proto (スキーム)を見るようにするという設定です。
app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto });
|
ASP.NET MVC Core 2.0のアプリケーションでHTTPSを強制するには、RequireHttpsフィルター(RequireHttpsAttributeクラス)をグローバルフィルターに追加することで実現できます。
public void ConfigureServices(IServiceCollection services) { services .AddMvc(options => { options.Filters.Add(new RequireHttpsAttribute()); }); }
|
注意点として、RequireHttpsAttributeフィルターはOnAuthorizationメソッド、つまりフィルターパイプラインの一番最初である認可フェーズで処理されるので、ほかの認証/認可フィルターはこのフィルターより後に登録する必要があります。
MicrosoftのサイトにはRewriteエンジンを使う方法も書かれていますが、大抵のケースではフィルターで追加する方法で間に合うと思います。
MVCを使わないASP.NET Coreでもリダイレクトしたい
また、MVCではないASP.NET Coreで同じようなことをしたい場合には以下のようなMiddlewareを書くとよいでしょう(動作未確認)。
public static IApplicationBuilder UseRedirectToHttps(this IApplicationBuilder app) { return app.Use((context, next) => { var req = context.Request; if (!req.IsHttps) { var newUrl = new StringBuilder().Append("https://").Append(req.Host.Host).Append(req.PathBase).Append(req.Path).Append(req.QueryString); context.Response.Redirect(newUrl.ToString(), permanent: true); return Task.CompletedTask; }
return next(); }); }
|
ところでグローバルなフィルターを追加するのはいいのですが、環境によっては例えばデバッグ実行時や開発環境では追加したくないということもあります。
Configure メソッド内であれば env.IsProduction() といった感じで切り替えできるのですが、ConfigureService メソッドには IHostingEnvironment が渡ってこないのです。
ではどうするかというと Startup クラスにプロパティやフィールドをはやして、保持しておくという方法で解決できます。まあ Configuration も保持してますしね。
public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); HostingEnvironment = env; }
public IHostingEnvironment HostingEnvironment { get; }
|
一度保持してしまえば ConfigureServices から参照可能になるので環境ごとに切り替えができます。
public void ConfigureServices(IServiceCollection services) { services .AddMvc(options => { if (HostingEnvironment.IsProduction()) { options.Filters.Add(new RequireHttpsAttribute()); } }); }
|