MVC RequireHttps entire site
I have read the previous posts about usin开发者_JS百科g the RequireHttpsAttribute to secure individual controllers:
ASP.NET MVC RequireHttps in Production Only
but is there a way to apply this to the entire site? Due to my host (discountasp.net) I cannot use the "RequireSSL IIS" setting.
Register the RequireHttpsAttribute
as a global filter.
In global.asax:
protected void Application_Start()
{
GlobalFilters.Filters.Add(new RequireHttpsAttribute());
//... other stuff
}
I ended up using IIS URL Rewrite 2.0 to force the site to switch to HTTPS. This code in web.config does the trick:
<system.webServer>
<!-- This uses URL Rewrite 2.0 to force the entire site into SSL mode -->
<rewrite xdt:Transform="Insert">
<rules>
<rule name="Force HTTPS" enabled="true">
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
You could always add a check at the application level in your global.asax
protected void Application_BeginRequest(Object sender, EventArgs e)
{
if (!HttpContext.Current.Request.IsSecureConnection)
{
Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"]
+ HttpContext.Current.Request.RawUrl);
}
}
Just to bring this answer upto date for MVC 3 and above use the following in your Filterconfig.cs file within the App_start folder
filters.Add(new RequireHttpsAttribute());
Obviously you will need your servers IIS configured to use a valid SSL certificate, cheap certs can be purchased here: https://www.namecheap.com/ i think the last time i purchased one it was $9 per domain per year.
In your FilterConfig.cs apply this:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// only if Debug is not enabled, do not require https for local development
if (!HttpContext.Current.IsDebuggingEnabled)
filters.Add(new RequireHttpsAttribute());
//... any other filters
}
That should force your app to use https on every page.
This isn't using RequireHttps
but I think it's a better solution because it catches the redirect sooner in the MVC Lifecycle.
public class RedirectModule : IHttpModule
{
private HttpApplication _context;
public void Init(HttpApplication context)
{
_context = context;
_context.PostResolveRequestCache += HttpRedirect;
}
public void HttpRedirect(Object src, EventArgs args)
{
if (_context.Request.Url.Scheme == Uri.UriSchemeHttp)
{
//Redirect to https
var scheme = Uri.UriSchemeHttps + "://";
var authority = _context.Request.Url.Authority;
var url = _context.Request.RawUrl;
var redirectTo = scheme + authority + url;
_context.Response.PermanentRedirect(redirectTo);
}
}
public void Dispose() { }
}
The idea came from this article.
You can register the module in your Web.config
or inside the Global.asax
. I'll show you in the web.cofig.
<system.webServer>
<modules>
<add name="ConfigModuleName" type="Your.Namespace.RedirectModule"/>
</modules>
</system.webServer>
MVC 6 (ASP.NET Core 1.0) works slightly different in it's way of registering filters:
Startup.cs - AddMvc with filter for RequireHttpsAttribute:
public void ConfigureServices(IServiceCollection services)
{
// TODO: Register other services
services.AddMvc(options =>
{
options.Filters.Add(typeof(RequireHttpsAttribute));
});
}
Design decisions explained:
- Use filter in Startup.cs for global setup (since we want this to apply everywhere). Startup should be responsible for registering and setting up all global rules. If your company employ a new developer, she would expect to find global setup in Startup.cs.
- Use RequireHttpsAttribute logic since it's proven (by Microsoft). Never use "magical" strings like "http://" and "https://" when it can be avoided by reusing a Microsoft component created to provide the same logic.
If you are running your MVC website in localhost without SSL:
- http://localhost:1337/ (no SSL)
- https://localhost:1337/ (SSL)
Consider looking at how to run without SSL in localhost while still requiring https it in production.
Note:
As an alternative, we could make a "class BaseController : Controller" and make all our controllers inherit from "BaseController" (instead of Controller). Then we only have to set the attribute 1 global place (and don't need to register filter in Startup.cs).
Some people prefer the attribute style.
Example of usage:
[RequireHttpsAttribute]
public class BaseController : Controller
{
// Maybe you have other shared controller logic..
}
public class HomeController : BaseController
{
// Add endpoints (GET / POST) for Home controller
}
In Global.asax.cs, use "RegisterGlobalFilters" to register global attributes.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new RequireHttpsAttribute());
//e.g. filters.Add(new HandleErrorAttribute());
//e.g. filters.Add(new System.Web.Mvc.AuthorizeAttribute());
}
You could use a base class for all of your controllers, and decorate that with the require ssl attribute.
精彩评论