Po wielu badaniach udało mi się rozwiązać ten problem za pomocą IIS Express i nadpisania metody OnAuthorization klasy kontrolera (Ref # 1). Poszedłem też trasą polecaną przez Hanselmana (Ref # 2). Jednak nie byłem w pełni usatysfakcjonowany tymi dwoma rozwiązaniami z dwóch powodów: 1. Autoryzacja OnAuthorization Ref # 1 działa tylko na poziomie akcji, a nie na poziomie klasy kontrolera 2. Ref # 2 wymaga dużo konfiguracji (Win7 SDK dla makecert ), polecenia netsh i, aby użyć portu 80 i portu 443, muszę uruchomić VS2010 jako administrator, na co marszczę brwi.
Tak więc wymyśliłem to rozwiązanie, które stawia na prostotę przy następujących warunkach:
Chcę móc używać attbbute RequireHttps na poziomie klasy kontrolera lub akcji
Chcę, aby MVC używał protokołu HTTPS, gdy atrybut RequireHttps jest obecny, i protokołu HTTP, jeśli go nie ma
Nie chcę uruchamiać programu Visual Studio jako administrator
Chcę mieć możliwość korzystania z dowolnych portów HTTP i HTTPS przypisanych przez IIS Express (patrz uwaga nr 1)
Mogę ponownie użyć samopodpisanego certyfikatu SSL programu IIS Express i nie obchodzi mnie, czy widzę nieprawidłowy monit SSL
Chcę, aby tworzenie, testowanie i produkcja miały dokładnie taką samą bazę kodu i ten sam plik binarny oraz były niezależne od dodatkowej konfiguracji (np. Przy użyciu netsh, przystawki mmc cert itp.)
Teraz, po usunięciu tła i wyjaśnień, mam nadzieję, że ten kod pomoże komuś i zaoszczędzi trochę czasu. Zasadniczo utwórz klasę BaseController, która dziedziczy po kontrolerze, i wyprowadź klasy kontrolera z tej klasy bazowej. Ponieważ przeczytałeś tak daleko, zakładam, że wiesz, jak to zrobić. Życzymy miłego kodowania!
Uwaga nr 1: Osiąga się to za pomocą użytecznej funkcji „getConfig” (patrz kod)
Nr ref. 1: http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
Nr ref. 2: http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx
========== Kod w BaseController ===================
#region Override to reroute to non-SSL port if controller action does not have RequireHttps attribute to save on CPU
// By L. Keng, 2012/08/27
// Note that this code works with RequireHttps at the controller class or action level.
// Credit: Various stackoverflow.com posts and http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
protected override void OnAuthorization(AuthorizationContext filterContext)
{
// if the controller class or the action has RequireHttps attribute
var requireHttps = (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0
|| filterContext.ActionDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0);
if (Request.IsSecureConnection)
{
// If request has a secure connection but we don't need SSL, and we are not on a child action
if (!requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "http",
Port = int.Parse(getConfig("HttpPort", "80")) // grab from config; default to port 80
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
else
{
// If request does not have a secure connection but we need SSL, and we are not on a child action
if (requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "https",
Port = int.Parse(getConfig("HttpsPort", "443")) // grab from config; default to port 443
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
base.OnAuthorization(filterContext);
}
#endregion
// a useful helper function to get appSettings value; allow caller to specify a default value if one cannot be found
internal static string getConfig(string name, string defaultValue = null)
{
var val = System.Configuration.ConfigurationManager.AppSettings[name];
return (val == null ? defaultValue : val);
}
============== kod końcowy ================
W Web.Release.Config dodaj następujący kod, aby wyczyścić HttpPort i HttpsPort (aby użyć domyślnych 80 i 443).
<appSettings>
<add key="HttpPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
<add key="HttpsPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
</appSettings>