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?

Это не поможет, если вы запускаете сборки 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

  • Как исправить ошибку компиляции Visual Studio, «несоответствие между архитектурой процессора»?
  • GCC с Visual Studio?
  • XML - данные на корневом уровне недействительны
  • WCF, тип возврата интерфейса и известные типы
  • Утверждение не выполнено (size.width> 0 && size.height> 0)
  • Можно ли установить Visual Studio 2012 бок о бок с Visual Studio 2010?
  • Анализ файлов решений Visual Studio
  • Аутентификация Windows IIS Express
  • Подавление «никогда не используется» и «никогда не назначается» предупреждениям в C #
  • Как я могу читать / записывать настройки app.config во время выполнения без использования пользовательских настроек?
  • Должен ли я компилироваться с / MD или / MT?
  • Interesting Posts

    Проблемы с jQuery getJSON с использованием локальных файлов в Chrome

    Селектор CSS, который применяется к элементам с двумя classами

    Как скрыть значок действия share (который используется больше всего) рядом с поставщиком акций?

    Что означает «(Install)» в пакете?

    Мне нужно установить MVC 3/4 на веб-сервере для запуска приложения mvc

    Самый простой способ чтения из URL-адреса в строку в .NET.

    Существует pmin и pmax, каждый из которых принимает na.rm, почему нет psum?

    Учитывая аудиоstream, найдите, когда дверь хлопает (расчет уровня звукового давления?)

    Отсутствие вывода консоли при использовании AllocConsole и целевой архитектуры x86

    Каковы некоторые лучшие практики и «эмпирические правила» для создания индексов базы данных?

    Получение данных из Android Play Store

    Автоматически отклонять попытки взлома в CentOS?

    Сценарий Bash для ожидания завершения работы Virtualbox VM?

    Включение цилиндра в сферу без защемления на полюсах

    Выполните задачу по удалению в android

    Давайте будем гением компьютера.