ASP.NET MVC: comment désactiver automatiquement [RequireHttps] sur localhost?

je veux que ma page de connexion à SSL uniquement:

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

        return View();
    }

mais évidemment cela ne fonctionne pas sur localhost quand je développe et debug mon application. Je ne veux pas utiliser IIS 7 avec des certificats SSL, comment désactiver automatiquement L'attribut RequireHttps?

mise à Jour

basé sur les informations fournies par les utilisateurs de StackOverflow et ASP.NET code source MVC 2 j'ai créé la classe suivante qui résout le problème.

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

Et il est utilisé comme ceci:

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

    return View();
}
26
demandé sur Alex 2010-09-02 18:37:46

5 réponses

La chose la plus facile serait de dériver un nouvel attribut de Requerhttps et d'outrepasser HandleNonHttpsRequest

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

HandleNonHttpsRequest est la méthode qui lance l'exception, ici tout ce que nous faisons n'est pas l'appeler si l'hôte est localhost (et comme Jeff le dit dans son commentaire, vous pouvez étendre cela aux environnements de test ou en fait toutes les autres exceptions que vous voulez).

26
répondu Chao 2016-09-12 11:10:49
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) {

        if (!HttpContext.Current.IsDebuggingEnabled) {
            filters.Add(new RequireHttpsAttribute());
        }
    }
17
répondu anon 2014-12-05 20:49:47
#if (!DEBUG)
[RequireHttps]
#endif
public ActionResult Login()
{
    if (Helper.LoggedIn)
    {
        Response.Redirect("/account/stats");
    }

    return View();
}
14
répondu Femaref 2010-09-02 14:46:00

Vous pouvez encapsuler cette exigence dans un attribut dérivé:

class RequireHttpsNonDebugAttribute : RequireHttpsAttribute {
    public override void HandleNonHttpsRequest(AuthorizationContext ctx) {
        #if (!DEBUG)
        base.HandleNonHttpsRequest(ctx);
        #endif
    }
}
8
répondu joshperry 2010-09-02 14:59:11

MVC 6 (ASP.NET Core 1.0):

la bonne solution serait d'utiliser env.IsProduction () ou env.IsDevelopment ().

Exemple:

Démarrage.cs - AddMvc avec un filtre personnalisé:

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

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

le filtre personnalisé hérite de 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);
    }
}

décisions de Design expliquées:

  1. Utilisation de l'environnement IsProduction() ou IsDevelopment() over par exemple "#if DEBUG". Parfois, nous publions/publions en mode DEBUG sur notre serveur de test et ne voulons pas désactiver cette exigence de sécurité. Cela ne doit être désactivé qu'en cas de développement local (puisque nous sommes trop paresseux pour configurer localhost SSL dans IIS Express ou quoi que nous utilisions localement).
  2. utiliser le filtre au démarrage.cs global de l'installation (puisque nous voulons que cela s'applique partout). Le démarrage doit être responsable de l'enregistrement et de la mise en place de toutes les règles globales. Si votre entreprise emploient un nouveau développeur, elle s'attend à trouver une configuration globale au démarrage.cs.
  3. Utiliser RequireHttpsAttribute logique puisque c'est prouvé (par Microsoft). La seule chose que nous voulons changer est quand la logique est appliquée (production) et quand elle ne l'est pas (Développement/localhost). N'utilisez jamais de chaînes" magiques "comme" http:// "et" https:// " lorsque cela peut être évité en réutilisant un composant Microsoft créé pour fournir la même logique.

ci-dessus je voudrais considérer la "bonne" solution.

Remarque:

autres, nous pourrions faire un " BaseController de classe: Controller "et faire hériter tous nos controllers de" BaseController " (au lieu de Controller). Alors nous n'avons qu'à définir l'attribut 1 global place (et n'avons pas besoin de filter au démarrage).cs).

certaines personnes préfèrent le style attribut. Veuillez noter que cela éliminera la décision de conception #2 avantage.

Exemple d'utilisation:

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

public class HomeController : BaseController
{
    // Add endpoints (GET / POST) for Home controller
}
1
répondu Nick Niebling 2016-07-07 12:03:11