2010-09-02 9 views
25

Voglio che la mia pagina di login per essere SSL solo:ASP.NET MVC: Come disabilitare automaticamente [RequireHttps] su localhost?

[RequireHttps] 
    public ActionResult Login() 
    { 
     if (Helper.LoggedIn) 
     { 
      Response.Redirect("/account/stats"); 
     } 

     return View(); 
    } 

Ma ovviamente non funziona su localhost quando sviluppo e il debug la mia domanda. Non voglio usare IIS 7 con i certificati SSL, come posso disabilitare automaticamente l'attributo RequireHttps?

Aggiornamento

Sulla base di informazioni fornite dagli utenti StackOverflow e il codice ASP.NET MVC 2 fonte ho creato la seguente classe che risolve il problema.

public class RequireSSLAttribute : FilterAttribute, IAuthorizationFilter 
{ 
    public virtual void OnAuthorization(AuthorizationContext filterContext) 
    { 
     if (filterContext == null) 
     { 
      throw new ArgumentNullException("filterContext"); 
     } 

     if (!filterContext.HttpContext.Request.IsSecureConnection) 
     { 
      HandleNonHttpsRequest(filterContext); 
     } 
    } 

    protected virtual void HandleNonHttpsRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.Url.Host.Contains("localhost")) return; 

     if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) 
     { 
      throw new InvalidOperationException("The requested resource can only be accessed via SSL"); 
     } 

     string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; 
     filterContext.Result = new RedirectResult(url); 
    } 
} 

Ed è usato in questo modo:

[RequireSSL] 
public ActionResult Login() 
{ 
    if (Helper.LoggedIn) 
    { 
     Response.Redirect("/account/stats"); 
    } 

    return View(); 
} 
+0

Se si cerca Stack Overflow per "RequireHttps" alla domanda è stato chiesto un paio di volte, così un sacco di informazioni per quanto riguarda la soluzione. È una buona domanda, tuttavia, non ho ancora usato quell'attributo, ma posso vedere che si tratta di un problema immediato. –

+0

Hai ragione. Il problema è stato risolto e ho aggiornato il mio post principale con la classe che mi ha aiutato. – Alex

risposta

25

La cosa più semplice sarebbe quella di ricavare un nuovo attributo da RequireHttps e ignorare HandleNonHttpsRequest

protected override void HandleNonHttpsRequest(AuthorizationContext filterContext) 
     { 
      if (!filterContext.HttpContext.Request.Url.Host.Contains("localhost")) 
      { 
       base.HandleNonHttpsRequest(filterContext); 
      } 
     } 

HandleNonHttpsRequest è il metodo che getta l'eccezione, qui tutto ciò che stiamo facendo non è chiamato se l'host è localhost (e come dice Jeff in il suo commento si potrebbe estendere questo per testare gli ambienti o in realtà tutte le altre eccezioni che si desidera).

+0

Questo metodo potrebbe essere modificato per non richiedere anche HTTPS negli ambienti di test. –

+0

Dove devo inserire questo codice? Aggiornamento Oh non importa, ho capito. – Alex

+0

Ho usato il codice e il codice sorgente di MVC per creare una soluzione. Grazie! – Alex

14
#if (!DEBUG) 
[RequireHttps] 
#endif 
public ActionResult Login() 
{ 
    if (Helper.LoggedIn) 
    { 
     Response.Redirect("/account/stats"); 
    } 

    return View(); 
} 
+2

Ho pensato anche a questo. Ma significa che devo aggiungere #if DEBUG per ogni attributo RequireHttps. – Alex

+0

ah, ho pensato che fosse solo una occasione. Le altre proposte sono migliori allora. – Femaref

8

È possibile incapsulare questo requisito in un attributo derivato:

class RequireHttpsNonDebugAttribute : RequireHttpsAttribute { 
    public override void HandleNonHttpsRequest(AuthorizationContext ctx) { 
     #if (!DEBUG) 
     base.HandleNonHttpsRequest(ctx); 
     #endif 
    } 
} 
17
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { 

     if (!HttpContext.Current.IsDebuggingEnabled) { 
      filters.Add(new RequireHttpsAttribute()); 
     } 
    } 
+0

Sarebbe più utile aggiungere alcune informazioni su dove inserire questo codice, solo per aiutare chi non ha familiarità con ASP.NET MVC. – Andrew

+4

Nel mio progetto MVC corrente, c'era un file predefinito nella cartella App_Start denominata FilterConfig.cs. Aggiungilo lì. – fabspro

1

MVC 6 (ASP.NET core 1.0):

La soluzione corretta sarebbe quella di utilizzare env.IsProduction() o env.IsDevelopment().

Esempio:

Startup.cs - AddMvc con un filtro personalizzato: Filtro

public void ConfigureServices(IServiceCollection services) 
{ 
    // TODO: Register other services 

    services.AddMvc(options => 
    { 
     options.Filters.Add(typeof(RequireHttpsInProductionAttribute)); 
    }); 
} 

personalizzate ereditano dalle decisioni 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); 
    } 
} 

design spiegato:

  1. Utilizzare l'ambiente IsProduction() o IsDevelopment() su es. "#if DEBUG". A volte rilasciamo/pubblichiamo in modalità DEBUG sul nostro server di test e non vogliamo disabilitare questo requisito di sicurezza. Questo deve essere disabilitato solo in localhost/sviluppo (dal momento che siamo troppo pigri per configurare localhost SSL in IIS Express o qualsiasi cosa usiamo localmente).
  2. Utilizzare il filtro in Startup.cs per l'installazione globale (poiché desideriamo che questo si applichi ovunque). L'avvio dovrebbe essere responsabile della registrazione e dell'impostazione di tutte le regole globali. Se la tua azienda impiega un nuovo sviluppatore, si aspetterebbe di trovare la configurazione globale in Startup.cs.
  3. Utilizzare la logica RequireHttpsAttribute poiché è stato provato (da Microsoft). L'unica cosa che vogliamo cambiare è quando viene applicata la logica (produzione) e quando non lo è (sviluppo/localhost). Non utilizzare mai stringhe "magiche" come "http: //" e "https: //" quando possono essere evitate riutilizzando un componente Microsoft creato per fornire la stessa logica.

Sopra vorrei prendere in considerazione la soluzione "corretta".

Nota:

Come alternativa, potremmo fare una "classe BaseController: Controller" e fare tutti i nostri controllori ereditano da "BaseController" (invece di Controller). Quindi dobbiamo solo impostare l'attributo 1 posto globale (e non è necessario registrare il filtro in Startup.cs).

Alcune persone preferiscono lo stile dell'attributo. Si prega di notare che questo eliminerà i vantaggi della decisione di design # 2.

Esempio di utilizzo:

[RequireHttpsInProductionAttribute] 
public class BaseController : Controller 
{ 
    // Maybe you have other shared controller logic.. 
} 

public class HomeController : BaseController 
{ 
    // Add endpoints (GET/POST) for Home controller 
}