ASP.NET MVC RequireHttps только в производстве

Я хочу использовать RequireHttpsAttribute для предотвращения отправки незапрашиваемых HTTP-запросов методу действия.

C #

[RequireHttps] //apply to all actions in controller public class SomeController { [RequireHttps] //apply to this action only public ActionResult SomeAction() { ... } } 

VB

  _ Public Class SomeController  _ Public Function SomeAction() As ActionResult ... End Function End Class 

К сожалению, ASP.NET Development Server не поддерживает HTTPS.

Как я могу заставить приложение ASP.NET MVC использовать RequireHttps при публикации в рабочей среде, но не при запуске на моей рабочей станции разработки на сервере разработки ASP.NET?

15 Solutions collect form web for “ASP.NET MVC RequireHttps только в производстве”

Это не поможет, если вы запускаете сборки Release на рабочей станции разработки, но условная компиляция может выполнить эту работу …

 #if !DEBUG [RequireHttps] //apply to all actions in controller #endif public class SomeController { //... or ... #if !DEBUG [RequireHttps] //apply to this action only #endif public ActionResult SomeAction() { } } 

Обновить

В Visual Basic атрибуты являются технически частью той же линии, что и определение, к которому они относятся. Вы не можете вводить условные инструкции компиляции внутри строки, поэтому вам приходится дважды писать объявление функции – один раз с атрибутом и один раз без него. Это действительно работает, если вы не против уродства.

 #If Not Debug Then  _ Function SomeAction() As ActionResult #Else Function SomeAction() As ActionResult #End If ... End Function 

Обновление 2

Несколько человек упомянули RequireHttpsAttribute из RequireHttpsAttribute не представив пример, так что вот один из них. Я думаю, что этот подход был бы намного чище, чем подход условной компиляции, и это было бы моим преимуществом в вашей позиции.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я не тестировал этот код, даже немного, и мой VB довольно ржавый. Все, что я знаю, это то, что он компилируется. Я написал его на основе предложений spot, queen3 и Lance Fisher. Если это не сработает, оно должно хотя бы передать общую идею и дать вам отправную точку.

 Public Class RemoteRequireHttpsAttribute Inherits System.Web.Mvc.RequireHttpsAttribute Public Overrides Sub OnAuthorization(ByVal filterContext As _ System.Web.Mvc.AuthorizationContext) If IsNothing(filterContext) Then Throw New ArgumentNullException("filterContext") End If If Not IsNothing(filterContext.HttpContext) AndAlso _ filterContext.HttpContext.Request.IsLocal Then Return End If MyBase.OnAuthorization(filterContext) End Sub End Class 

В принципе, новый атрибут просто завершает работу вместо того, чтобы запускать код авторизации SSL по умолчанию, если текущий запрос является локальным (то есть вы получаете доступ к сайту через localhost). Вы можете использовать его следующим образом:

  _ Public Class SomeController  _ Public Function SomeAction() As ActionResult ... End Function End Class 

Гораздо чище! Если мой незапрошенный код действительно работает.

Если кому-то нужна версия C #:

 using System; using System.Web.Mvc; namespace My.Utils { public class MyRequireHttpsAttribute : RequireHttpsAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } if (filterContext.HttpContext != null && filterContext.HttpContext.Request.IsLocal) { return; } base.OnAuthorization(filterContext); } } } 

Вывод из RequireHttps – хороший подход.

Чтобы устранить проблему полностью, вы можете использовать IIS на своей локальной машине с самозаверяющим сертификатом. IIS быстрее, чем встроенный веб-сервер, и у вас есть то преимущество, что ваша среда разработки больше похожа на производство.

Скотт Гензельман обладает отличным ресурсом по нескольким способам реализации локальных HTTPS с VS2010 и IIS Express.

Используя систему фильтров MVC и Global.asax.cs, я предполагаю, что вы можете это сделать …

  protected void Application_Start() { RegisterGlobalFilters(GlobalFilters.Filters); } public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); if(Config.IsProduction) //Some flag that you can tell if you are in your production environment. { filters.Add(new RequireHttpsAttribute()); } } 

Поскольку именно ASP.Net Development Server вызвал вашу проблему в первую очередь, стоит отметить, что Microsoft теперь имеет IIS Express , который поставляется с Visual Studio (начиная с VS2010 SP1). Это сокращенная версия IIS, которая так же проста в использовании, как и сервер разработки, но поддерживает полный набор функций IIS 7.5, включая SSL.

У Скотта Ханзельмана есть подробное сообщение о работе с SSL в IIS Express .

Как насчет наследования атрибута RequireHttps в пользовательском атрибуте. Затем, внутри вашего настраиваемого атрибута, проверьте свойство IsLocal текущего запроса, чтобы узнать, поступает ли запрос с локальной машины. Если это так, не применяйте базовую функциональность. В противном случае вызовите базовую операцию.

Это сработало для меня MVC 6 (ASP.NET Core 1.0) . Код проверяет, находится ли debug в разработке, а если нет, ssl не требуется. Все изменения находятся в Startup.cs .

Добавить:

 private IHostingEnvironment CurrentEnvironment { get; set; } 

Добавить:

 public Startup(IHostingEnvironment env) { CurrentEnvironment = env; } 

Редактировать:

 public void ConfigureServices(IServiceCollection services) { // additional services... services.AddMvc(options => { if (!CurrentEnvironment.IsDevelopment()) { options.Filters.Add(typeof(RequireHttpsAttribute)); } }); } 

Если вы можете получить и переопределить – сделайте это. Если вы не можете – MVC поставляется с источниками, просто возьмите источники и создайте свой собственный атрибут [ForceHttps], который проверяет IsLocal.

Для MVC 3 я добавил свой собственный фильтр FilterProvider (на основе кода, найденного здесь: Глобальные и условные фильтры, которые, помимо прочего, отображают информацию об RequireHttpsAttribute для локальных пользователей и т. Д.), RequireHttpsAttribute все действия с помощью RequireHttpsAttribute когда HttpContext.Request.IsLocal == false .

После изучения aroud я смог решить эту проблему с помощью IIS Express и переопределить метод OnAuthorization classа Controller (ссылка № 1). Я также отправился с маршрутом, рекомендованным Hanselman (Ref № 2). Однако я не был полностью доволен этими двумя решениями по двум причинам: 1. OnAuthorization Ref # 1 работает только на уровне действия, а не на уровне controllerа 2-го уровня. Ссылка № 2 требует большой настройки (Win7 SDK для makecert ), netsh, и, чтобы использовать порт 80 и порт 443, мне нужно запустить VS2010 как администратор, на который я нахмурился.

Итак, я придумал это решение, которое фокусируется на простоте со следующими условиями:

  1. Я хочу иметь возможность использовать RequireHttps attbbute в classе Controller или уровне действия

  2. Я хочу, чтобы MVC использовал HTTPS, когда присутствует атрибут RequireHttps, и используйте HTTP, если он отсутствует

  3. Я не хочу запускать Visual Studio в качестве администратора

  4. Я хочу иметь возможность использовать любые HTTP и HTTPS-порты, назначенные IIS Express (см. Примечание № 1)

  5. Я могу повторно использовать самоподписанный SSL-сертификат IIS Express, и мне все равно, вижу ли я неверную подсказку SSL

  6. Я хочу, чтобы dev, test и production имели ту же самую базу кода и одну и ту же двоичную и независимую от дополнительной настройки (например, используя netsh, mmc cert snap-in и т. Д.), Насколько это возможно

Теперь, с учетом фона и объяснений, я надеюсь, что этот код поможет кому-то и сэкономит время. В принципе, создайте class BaseController, который наследуется от Controller, и выведите classы controllerа из этого базового classа. Поскольку вы зачитали это далеко, я предполагаю, что вы знаете, как это сделать. Итак, счастливое кодирование!

Примечание # 1: Это достигается за счет использования полезной функции getConfig (см. Код)

Ссылка № 1: http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html

Ссылка № 2: http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx

========== Код в 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); } 

============== конечный код ================

В Web.Release.Config добавьте следующее, чтобы очистить HttpPort и HttpsPort (использовать значения по умолчанию 80 и 443).

     

Одно решение, которое вы можете использовать на производстве, а также на рабочей станции разработки. Он основан на вашей опции из настроек приложения в web.config

     

Если вы не хотите использовать SSL, удалите ключ. Если вы используете стандартный порт SSL 443, удалите значение или укажите 443.

Затем используйте пользовательскую реализацию RequireHttpsAttribute, которая позаботится о вашем состоянии. Он фактически получен из RequireHttps и использует ту же реализацию базового метода, за исключением добавления условий.

 public class RequireHttpsConditional : RequireHttpsAttribute { protected override void HandleNonHttpsRequest(AuthorizationContext filterContext) { var useSslConfig = ConfigurationManager.AppSettings["UseSSL"]; if (useSslConfig != null) { if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("The requested resource can only be accessed via SSL."); } var request = filterContext.HttpContext.Request; string url = null; int sslPort; if (Int32.TryParse(useSslConfig, out sslPort) && sslPort > 0) { url = "https://" + request.Url.Host + request.RawUrl; if (sslPort != 443) { var builder = new UriBuilder(url) {Port = sslPort}; url = builder.Uri.ToString(); } } if (sslPort != request.Url.Port) { filterContext.Result = new RedirectResult(url); } } } } 

Не забудьте украсить метод LogOn в AccountController

 [RequireHttpsConditional] [HttpPost] public ActionResult LogOn(LogOnModel model, string returnUrl) 

и что-то вроде этого в вашем LogOn View, чтобы отправить форму через https.

 < % using (Html.BeginFormSecure("LogOn", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] }, Request.IsSecureConnection, Request.Url)) { %> 

Как сказал Джоэл, вы можете изменить компиляцию, используя #if !DEBUG .

Я только что узнал, что вы можете изменить значение символа DEBUG в элементе компиляции файла web.config. Надеюсь, это поможет.

MVC 6 (ASP.NET Core 1.0):

Правильным решением было бы использовать env.IsProduction () или env.IsDevelopment (). Узнайте больше о причине в этом ответе о том, как требовать https только в производстве .

Сжатый ответ ниже (см. Ссылку выше, чтобы узнать больше о дизайнерских решениях) для двух разных стилей:

  1. Startup.cs – фильтр регистрации
  2. BaseController – стиль атрибута

Startup.cs (фильтр регистрации):

 public void ConfigureServices(IServiceCollection services) { // TODO: Register other services services.AddMvc(options => { options.Filters.Add(typeof(RequireHttpsInProductionAttribute)); }); } 

BaseController.cs (стиль атрибута):

 [RequireHttpsInProductionAttribute] public class BaseController : Controller { // Maybe you have other shared controller logic.. } public class HomeController : BaseController { // Add endpoints (GET / POST) for Home controller } 

RequireHttpsInProductionAttribute : оба из них используют собственный атрибут, наследующий от RequireHttpsAttribute :

 public class RequireHttpsInProductionAttribute : RequireHttpsAttribute { private bool IsProduction { get; } public RequireHttpsInProductionAttribute(IHostingEnvironment environment) { if (environment == null) throw new ArgumentNullException(nameof(environment)); this.IsProduction = environment.IsProduction(); } public override void OnAuthorization(AuthorizationContext filterContext) { if (this.IsProduction) base.OnAuthorization(filterContext); } protected override void HandleNonHttpsRequest(AuthorizationContext filterContext) { if(this.IsProduction) base.HandleNonHttpsRequest(filterContext); } } 

Это был самый чистый путь для меня. В моем App_Start\FilterConfig.cs . Больше не могу запускать сборки релизов.

 ... public static void RegisterGlobalFilters(GlobalFilterCollection filters) { if (!Web.HttpContext.Current.IsDebuggingEnabled) { filters.Add(new RequireHttpsAttribute()); } ... } 

В качестве альтернативы вы можете установить для него только https, когда включена пользовательская страница ошибок.

 ... public static void RegisterGlobalFilters(GlobalFilterCollection filters) { if (Web.HttpContext.Current.IsCustomErrorEnabled) { filters.Add(new RequireHttpsAttribute()); } ... } 

Пожалуйста, обратитесь к этому сообщению от Рика Андерсона на RickAndMSFT на Azure & MVC, заполняющем лазурный пробел

http://blogs.msdn.com/b/rickandy/archive/2011/04/22/better-faster-easier-ssl-testing-for-asp-net-mvc-amp-webforms.aspx

  • Почему опция «Установить как старт» хранится в файле suo, а не в sln-файле?
  • Почему Visual Studio 2010 не может найти / открыть файлы PDB?
  • В чем разница между параметрами компилятора / Ox и / O2?
  • Можно ли установить LARGEADDRESSAWARE из Visual Studio?
  • Разница между Rebuild и Clean + Build в Visual Studio
  • Не удается запустить веб-приложение ASP.NET MVC 2 на IIS 7.5
  • Скрытые возможности Visual Studio (2005-2010)?
  • Как выполнить команды процесса (или аналогичные) с помощью приложения Universal Windows Platform (UWP)?
  • Пользовательский путь для user.config
  • Порядок инициализации статических переменных
  • Аутентификация Windows IIS Express
  • Давайте будем гением компьютера.