Страницы SSL в ASP.NET MVC

Как я могу использовать HTTPS для некоторых страниц на моем сайте ASP.NET MVC?

Стив Сандерсон имеет довольно хороший учебник о том, как это сделать DRY на Preview 4 в:

http://blog.codeville.net/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/

Есть ли лучший / обновленный способ с Preview 5 ?,

Если вы используете ASP.NET MVC 2 Preview 2 или выше , теперь вы можете просто использовать:

[RequireHttps] public ActionResult Login() { return View(); } 

Хотя, параметр порядка стоит отметить, как упоминалось здесь .

MVCFutures имеет атрибут RequireSSL.

(спасибо Адаму за то, что вы указали это в своем обновленном блоге)

Просто примените его к вашему методу действий с помощью «Redirect = true», если вы хотите, чтобы запрос http: // автоматически стал https: //:

  [RequireSsl(Redirect = true)] 

См. Также: ASP.NET MVC RequireHttps только в производстве

Как писал Amadiere , [RequireHttps] отлично работает в MVC 2 для ввода HTTPS. Но если вы хотите использовать HTTPS только для некоторых страниц, как вы сказали, MVC 2 не дает вам никакой любви – как только он переключит пользователя на HTTPS, они застряли там, пока вы не перенаправите их вручную.

Подход, который я использовал, заключается в использовании другого настраиваемого атрибута [ExitHttpsIfNotRequired]. При подключении к controllerу или действию он перенаправляет на HTTP, если:

  1. Запрос был HTTPS
  2. Атрибут [RequireHttps] не применялся к действию (или controllerу)
  3. Запрос был GET (redirect POST приведет к разным проблемам).

Здесь слишком много сообщений, но вы можете увидеть здесь код и дополнительные сведения.

Вот последнее сообщение от Дэна Вахлина по этому поводу:

http://weblogs.asp.net/dwahlin/archive/2009/08/25/requiring-ssl-for-asp-net-mvc-controllers.aspx

Он использует атрибут ActionFilter.

Некоторые расширения ActionLink: http://www.squaredroot.com/post/2008/06/11/MVC-and-SSL.aspx Или атрибут действия controllerа, который перенаправляется на https: // http://forums.asp.net /p/1260198/2358380.aspx#2358380

Для тех, кто не является поклонником ориентированных на атрибуты подходов к разработке, вот fragment кода, который может помочь:

 public static readonly string[] SecurePages = new[] { "login", "join" }; protected void Application_AuthorizeRequest(object sender, EventArgs e) { var pageName = RequestHelper.GetPageNameOrDefault(); if (!HttpContext.Current.Request.IsSecureConnection && (HttpContext.Current.Request.IsAuthenticated || SecurePages.Contains(pageName))) { Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"] + HttpContext.Current.Request.RawUrl); } if (HttpContext.Current.Request.IsSecureConnection && !HttpContext.Current.Request.IsAuthenticated && !SecurePages.Contains(pageName)) { Response.Redirect("http://" + Request.ServerVariables["HTTP_HOST"] + HttpContext.Current.Request.RawUrl); } } 

Есть несколько причин избежать атрибутов, и один из них – это если вы хотите посмотреть список всех защищенных страниц, которые вам придется перепрыгивать через все controllerы в решении.

Я пошел по этому вопросу и надеюсь, что мое решение может помочь кому-то.

У нас мало проблем: – Нам нужно обеспечить определенные действия, например «LogOn» в «Учетной записи». Мы можем использовать сборку в атрибуте RequireHttps, что отлично, но оно перенаправит нас с помощью https: //. – Мы должны делать наши ссылки, формы и такие «SSL-уведомления».

Как правило, мое решение позволяет указать маршруты, которые будут использовать абсолютный URL, в дополнение к возможности указывать протокол. Этот протокол можно использовать для указания протокола «https».

Итак, во-первых, я создал перечисление ConnectionProtocol:

 ///  /// Enum representing the available secure connection requirements ///  public enum ConnectionProtocol { ///  /// No secure connection requirement ///  Ignore, ///  /// No secure connection should be used, use standard http request. ///  Http, ///  /// The connection should be secured using SSL (https protocol). ///  Https } 

Теперь я создал ручную версию RequireSsl. Я изменил исходный исходный код RequireSsl, чтобы перенаправить обратно на http: // urls. Кроме того, я поместил поле, которое позволяет нам определить, нужно ли нам требовать SSL или нет (я использую его с предварительным процессором DEBUG).

 /* Note: * This is hand-rolled version of the original System.Web.Mvc.RequireHttpsAttribute. * This version contains three improvements: * - Allows to redirect back into http:// addresses, based on the  Requirement property. * - Allows to turn the protocol scheme redirection off based on given condition. * - Using Request.IsCurrentConnectionSecured() extension method, which contains fix for load-balanced servers. */ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public sealed class RequireHttpsAttribute : FilterAttribute, IAuthorizationFilter { public RequireHttpsAttribute() { Protocol = ConnectionProtocol.Ignore; } ///  /// Gets or sets the secure connection required protocol scheme level ///  public ConnectionProtocol Protocol { get; set; } ///  /// Gets the value that indicates if secure connections are been allowed ///  public bool SecureConnectionsAllowed { get { #if DEBUG return false; #else return true; #endif } } public void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } /* Are we allowed to use secure connections? */ if (!SecureConnectionsAllowed) return; switch (Protocol) { case ConnectionProtocol.Https: if (!filterContext.HttpContext.Request.IsCurrentConnectionSecured()) { HandleNonHttpsRequest(filterContext); } break; case ConnectionProtocol.Http: if (filterContext.HttpContext.Request.IsCurrentConnectionSecured()) { HandleNonHttpRequest(filterContext); } break; } } private void HandleNonHttpsRequest(AuthorizationContext filterContext) { // only redirect for GET requests, otherwise the browser might not propagate the verb and request // body correctly. if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("The requested resource can only be accessed via SSL."); } // redirect to HTTPS version of page string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; filterContext.Result = new RedirectResult(url); } private void HandleNonHttpRequest(AuthorizationContext filterContext) { if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("The requested resource can only be accessed without SSL."); } // redirect to HTTP version of page string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; filterContext.Result = new RedirectResult(url); } } 

Теперь этот RequireSsl выполнит следующую базу в вашем атрибуте атрибута требований: – Игнорировать: ничего не сделает. – Http: принудительно перенаправляет протокол http. – Https: принудительно перенаправляет протокол https.

Вы должны создать свой собственный базовый controller и установить этот атрибут в Http.

 [RequireSsl(Requirement = ConnectionProtocol.Http)] public class MyController : Controller { public MyController() { } } 

Теперь в каждом cpntroller / action, который вы хотите использовать SSL, просто установите этот атрибут с помощью ConnectionProtocol.Https.

Теперь переходим к URL-адресам: у нас мало проблем с движком маршрутизации URL. Подробнее о них вы можете узнать по адресу http://blog.stevensanderson.com/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/ . Решение, предложенное в этой статье, теоретически хорошо, но старое, и мне не нравится это утверждение.

Мои решения заключаются в следующем: Создайте подclass базового classа «Маршрут»:

public class AbsoluteUrlRoute: Маршрут {#region ctor

  ///  /// Initializes a new instance of the System.Web.Routing.Route class, by using /// the specified URL pattern and handler class. ///  /// The URL pattern for the route. /// The object that processes requests for the route. public AbsoluteUrlRoute(string url, IRouteHandler routeHandler) : base(url, routeHandler) { } ///  /// Initializes a new instance of the System.Web.Routing.Route class, by using /// the specified URL pattern and handler class. ///  /// The URL pattern for the route. /// The values to use for any parameters that are missing in the URL. /// The object that processes requests for the route. public AbsoluteUrlRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler) { } ///  /// Initializes a new instance of the System.Web.Routing.Route class, by using /// the specified URL pattern and handler class. ///  /// The URL pattern for the route. /// The values to use for any parameters that are missing in the URL. /// A regular expression that specifies valid values for a URL parameter. /// The object that processes requests for the route. public AbsoluteUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler) : base(url, defaults, constraints, routeHandler) { } ///  /// Initializes a new instance of the System.Web.Routing.Route class, by using /// the specified URL pattern and handler class. ///  /// The URL pattern for the route. /// The values to use for any parameters that are missing in the URL. /// A regular expression that specifies valid values for a URL parameter. /// Custom values that are passed to the route handler, but which are not used /// to determine whether the route matches a specific URL pattern. These values /// are passed to the route handler, where they can be used for processing the /// request. /// The object that processes requests for the route. public AbsoluteUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler) : base(url, defaults, constraints, dataTokens, routeHandler) { } #endregion public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { var virtualPath = base.GetVirtualPath(requestContext, values); if (virtualPath != null) { var scheme = "http"; if (this.DataTokens != null && (string)this.DataTokens["scheme"] != string.Empty) { scheme = (string) this.DataTokens["scheme"]; } virtualPath.VirtualPath = MakeAbsoluteUrl(requestContext, virtualPath.VirtualPath, scheme); return virtualPath; } return null; } #region Helpers ///  /// Creates an absolute url ///  /// The request context /// The initial virtual relative path /// The protocol scheme /// The absolute URL private string MakeAbsoluteUrl(RequestContext requestContext, string virtualPath, string scheme) { return string.Format("{0}://{1}{2}{3}{4}", scheme, requestContext.HttpContext.Request.Url.Host, requestContext.HttpContext.Request.ApplicationPath, requestContext.HttpContext.Request.ApplicationPath.EndsWith("/") ? "" : "/", virtualPath); } #endregion } 

Эта версия classа «Маршрут» создаст абсолютный URL-адрес. Трюк здесь, за которым следует предложение автора сообщения в блоге, заключается в использовании DataToken для указания схемы (пример в конце :)).

Теперь, если мы создадим URL-адрес, например, для маршрута «Account / LogOn», мы получим «/ http://example.com/Account/LogOn » – это с тех пор, как UrlRoutingModule видит все URL как относительные. Мы можем исправить это, используя пользовательский HttpModule:

 public class AbsoluteUrlRoutingModule : UrlRoutingModule { protected override void Init(System.Web.HttpApplication application) { application.PostMapRequestHandler += application_PostMapRequestHandler; base.Init(application); } protected void application_PostMapRequestHandler(object sender, EventArgs e) { var wrapper = new AbsoluteUrlAwareHttpContextWrapper(((HttpApplication)sender).Context); } public override void PostResolveRequestCache(HttpContextBase context) { base.PostResolveRequestCache(new AbsoluteUrlAwareHttpContextWrapper(HttpContext.Current)); } private class AbsoluteUrlAwareHttpContextWrapper : HttpContextWrapper { private readonly HttpContext _context; private HttpResponseBase _response = null; public AbsoluteUrlAwareHttpContextWrapper(HttpContext context) : base(context) { this._context = context; } public override HttpResponseBase Response { get { return _response ?? (_response = new AbsoluteUrlAwareHttpResponseWrapper(_context.Response)); } } private class AbsoluteUrlAwareHttpResponseWrapper : HttpResponseWrapper { public AbsoluteUrlAwareHttpResponseWrapper(HttpResponse response) : base(response) { } public override string ApplyAppPathModifier(string virtualPath) { int length = virtualPath.Length; if (length > 7 && virtualPath.Substring(0, 7) == "/http:/") return virtualPath.Substring(1); else if (length > 8 && virtualPath.Substring(0, 8) == "/https:/") return virtualPath.Substring(1); return base.ApplyAppPathModifier(virtualPath); } } } } 

Поскольку этот модуль переопределяет базовую реализацию UrlRoutingModule, мы должны удалить базовый httpModule и зарегистрировать наш в web.config. Итак, в разделе «system.web»:

      

Это оно :).

Чтобы зарегистрировать абсолютный / протокол, следующий по маршруту, вы должны сделать:

  routes.Add(new AbsoluteUrlRoute("Account/LogOn", new MvcRouteHandler()) { Defaults = new RouteValueDictionary(new {controller = "Account", action = "LogOn", area = ""}), DataTokens = new RouteValueDictionary(new {scheme = "https"}) }); 

Будем рады услышать ваши отзывы + улучшения. Надеюсь, это поможет! 🙂

Изменить: я забыл включить метод расширения IsCurrentConnectionSecured () (слишком много fragmentов: P). Это метод расширения, который обычно использует Request.IsSecuredConnection. Однако этот подход не будет работать при использовании балансировки нагрузки – поэтому этот метод может обойти это (взято из nopCommerce).

  ///  /// Gets a value indicating whether current connection is secured ///  /// The base request context /// true - secured, false - not secured /// nopCommerce WebHelper IsCurrentConnectionSecured()]]> public static bool IsCurrentConnectionSecured(this HttpRequestBase request) { return request != null && request.IsSecureConnection; // when your hosting uses a load balancer on their server then the Request.IsSecureConnection is never got set to true, use the statement below // just uncomment it //return request != null && request.ServerVariables["HTTP_CLUSTER_HTTPS"] == "on"; } 

Вот сообщение в блоге Pablo M. Cibrano с января 2009 года, в котором собраны несколько методов, включая методы HttpModule и расширения.

Вот сообщение в блоге Адама Сальво, в котором используется ActionFilter.

Это не обязательно зависит от MVC, но это решение действительно работает как для ASP.NET WebForms, так и для MVC:

http://www.codeproject.com/KB/web-security/WebPageSecurity_v2.aspx

Я использовал это в течение нескольких лет и как разделение проблем и управления с помощью файла web.config.

MVC 6 (ASP.NET Core 1.0) немного отличается от Startup.cs.

Чтобы использовать RequireHttpsAttribute (как указано в ответе Amadiere) на всех страницах, вы можете добавить это в Startup.cs вместо использования стиля атрибута на каждом controllerе (или вместо создания BaseController для всех ваших controllerов, наследуемых от).

Startup.cs – зарегистрировать фильтр:

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

Для получения дополнительной информации о проектных решениях для вышеуказанного подхода см. Мой ответ на аналогичный вопрос о том, как исключить запросы localhost из запроса RequireHttpsAttribute .

  • Запретить Google Chrome «Ваше подключение не является частным» для конкретного адреса?
  • Как сообщить `ссылкам` игнорировать истекший SSL-сертификат и продолжить?
  • SSLHandshakeException: сообщение о нарушении не выполнено на Android N / 7.0
  • Проверка подлинности клиента HTTPS на Java
  • Как создать самозаверяющий сертификат с помощью SubjectAltName с помощью OpenSSL?
  • Heroku NodeJS http to https ssl принудительное redirect
  • Как использовать TLS 1.2 в Java 6
  • Сертификату SSL не доверяют - только на мобильных телефонах
  • Force SSL / HTTPS с mod_rewrite
  • Как включить SSL 3 в Java
  • Что такое Keystore?
  • Interesting Posts

    Удалить кавычки из символьного вектора в R

    SQLException: Не найдено подходящего драйвера для jdbc: derby: // localhost: 1527

    Заполнитель HTML5 исчезает в фокусе

    Как установить получателей для UIActivityViewController в iOS 6?

    Как получить plist как словарь в Swift?

    Повышение производительности многопоточных HttpWebRequests в .NET.

    Как я могу исправить приложение Windows .NET при запуске с кодом исключения: 0xE0434352?

    Примеры контейнеров IoC

    Как определить общие подстроки в списке строк

    Как я могу остановить MySQL-запрос, если он занимает слишком много времени?

    неизвестная ошибка: результат функции вызова отсутствует «значение» для Selenium Send Keys даже после обновления хромированной передачи

    Изменить расширяемый индикатор в ExpandableListView

    В чем разница между lapply и do.call?

    Генерирование всех возможных перестановок списка рекурсивно

    Как включить и выключить перетаскивание окна при перетаскивании окна перетаскивания в окно 7?

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