[Asp.net-mvc] ASP.NET MVC RequireHttps solo in produzione


Answers

Se qualcuno ha bisogno della versione 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);
        }
    }
}
Question

Voglio utilizzare RequireHttpsAttribute per impedire che richieste HTTP non protette vengano inviate a un metodo di azione.

C #

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

VB

<RequireHttps()> _
Public Class SomeController

    <RequireHttps()> _
    Public Function SomeAction() As ActionResult
        ...
    End Function

End Class

Sfortunatamente, ASP.NET Development Server non supporta HTTPS.

Come posso fare in modo che la mia applicazione ASP.NET MVC utilizzi RequireHttps quando viene pubblicata nell'ambiente di produzione, ma non quando viene eseguita sulla mia workstation di sviluppo sul server di sviluppo ASP.NET?




Come menzionato da Joel, è possibile modificare la compilazione usando la direttiva #if !DEBUG .

Ho appena scoperto che è possibile modificare il valore del simbolo DEBUG nell'elemento di compilazione del file web.config. Spero possa aiutare.




Che ne dici di ereditare l'attributo RequireHttps in un attributo personalizzato. Quindi, all'interno dell'attributo personalizzato, controllare la proprietà IsLocal della richiesta corrente per verificare se la richiesta proviene dal computer locale. Se lo è, non applicare la funzionalità di base. Altrimenti, chiama l'operazione di base.




Sfruttando il sistema di filtri MVC e Global.asax.cs, suppongo che tu possa fare questo ...

    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());
      }
    }



Questo era il modo più pulito per me. Nel mio file App_Start\FilterConfig.cs . Non posso più eseguire build di rilascio però.

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

In alternativa, è possibile impostarlo per richiedere solo https quando la pagina di errore personalizzata è attiva.

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



Una soluzione che puoi utilizzare sia sulla produzione che sulla workstation di sviluppo. Si basa sulla tua opzione dalle impostazioni dell'applicazione in web.config

<appSettings>
     <!--Use SSL port 44300 in IIS Express on development workstation-->
     <add key="UseSSL" value="44300" />
</appSettings>

Se non si desidera utilizzare SSL, rimuovere la chiave. Se si utilizza la porta SSL standard 443, rimuovere il valore o specificare 443.

Quindi utilizzare l'implementazione personalizzata di RequireHttpsAttribute che si prende cura delle proprie condizioni. È derivato in realtà da RequireHttps e utilizza la stessa implementazione del metodo base tranne per l'aggiunta di condizioni.

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);
            }
        }
    }
}

Non dimenticare di decorare il metodo LogOn in AccountController

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

e qualcosa di simile nella tua vista di LogOn per poter pubblicare moduli su https.

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



Per MVC 3 ho aggiunto il mio FilterProvider (basato sul codice trovato qui: Filtri globali e condizionali che, tra le altre cose (visualizzazione di informazioni di debug per utenti locali ecc.) RequireHttpsAttribute tutte le azioni con RequireHttpsAttribute quando HttpContext.Request.IsLocal == false .