75 votes

L'authentification par formulaire: désactiver la redirection vers la page de connexion

J'ai une application qui utilise ASP.NET l'Authentification par Formulaires. Pour la plupart, c'est vraiment génial de travailler, mais je vais essayer d'ajouter le support pour une simple API via un .ashx fichier. Je veux que le fichier ashx de disposer en option d'authentification (c'est à dire si vous ne fournissez pas un en-tête d'Authentification, puis il fonctionne de manière anonyme). Mais, selon ce que vous faites, je veux exiger l'authentification sous certaines conditions.

Je pensais que ce serait une simple question de répondre avec le code d'état 401 si l'authentification n'a pas été fourni, mais il semble que les Formes Authentcation module est d'intercepter et de répondre avec une redirection vers la page de connexion à la place. Ce que je veux dire c'est, si mes ProcessRequest méthode ressemble à ceci:

public void ProcessRequest(HttpContext context)
{
    Response.StatusCode = 401;
    Response.StatusDescription = "Authentication required";
}

Alors au lieu d'obtenir un code d'erreur 401 sur le client, comme j'attends, je suis effectivement d'obtenir une redirection 302 vers la page de connexion.

Pour nornal le trafic HTTP, je peux voir comment cela pourrait être utile, mais pour mon API page, je veux la 401 à passer par des non modifiée de sorte que le côté client de l'appelant peut répondre par programmation à la place.

Est-il possible de faire cela?

82voto

zacharydl Points 1294

ASP.NET 4.5 ajouté le Booléen HttpResponse.SuppressFormsAuthenticationRedirect de la propriété.

public void ProcessRequest(HttpContext context)
{
    Response.StatusCode = 401;
    Response.StatusDescription = "Authentication required";
    Response.SuppressFormsAuthenticationRedirect = true;
}

37voto

Dean Harding Points 40164

Après une petite enquête, il semble que la FormsAuthenticationModule ajoute un gestionnaire pour l' HttpApplicationContext.EndRequest événement. Dans ce gestionnaire, il vérifie un 401 code d'état, et fait un Response.Redirect(loginUrl) à la place. Aussi loin que je peux dire, il n'y a aucun moyen de contourner ce comportement si vous voulez l'utiliser FormsAuthenticationModule.

La façon dont j'ai fini par trouver autour de celle-ci par la désactivation de l' FormsAuthenticationModule dans le web.config comme ceci:

<authentication mode="None" />

Et puis la mise en œuvre de l' Application_AuthenticateEvent moi-même:

void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (Context.User == null)
    {
        var oldTicket = ExtractTicketFromCookie(Context, FormsAuthentication.FormsCookieName);
        if (oldTicket != null && !oldTicket.Expired)
        {
            var ticket = oldTicket;
            if (FormsAuthentication.SlidingExpiration)
            {
                ticket = FormsAuthentication.RenewTicketIfOld(oldTicket);
                if (ticket == null)
                    return;
            }

            Context.User = new GenericPrincipal(new FormsIdentity(ticket), new string[0]);
            if (ticket != oldTicket)
            {
                // update the cookie since we've refreshed the ticket
                string cookieValue = FormsAuthentication.Encrypt(ticket);
                var cookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName] ??
                             new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue) { Path = ticket.CookiePath };

                if (ticket.IsPersistent)
                    cookie.Expires = ticket.Expiration;
                cookie.Value = cookieValue;
                cookie.Secure = FormsAuthentication.RequireSSL;
                cookie.HttpOnly = true;
                if (FormsAuthentication.CookieDomain != null)
                    cookie.Domain = FormsAuthentication.CookieDomain;
                Context.Response.Cookies.Remove(cookie.Name);
                Context.Response.Cookies.Add(cookie);
            }
        }
    }
}

private static FormsAuthenticationTicket ExtractTicketFromCookie(HttpContext context, string name)
{
    FormsAuthenticationTicket ticket = null;
    string encryptedTicket = null;

    var cookie = context.Request.Cookies[name];
    if (cookie != null)
    {
        encryptedTicket = cookie.Value;
    }

    if (!string.IsNullOrEmpty(encryptedTicket))
    {
        try
        {
            ticket = FormsAuthentication.Decrypt(encryptedTicket);
        }
        catch
        {
            context.Request.Cookies.Remove(name);
        }

        if (ticket != null && !ticket.Expired)
        {
            return ticket;
        }

        // if the ticket is expired then remove it
        context.Request.Cookies.Remove(name);
        return null;
    }
}

C'est effectivement un peu plus compliqué que ça, mais en gros, j'ai obtenu le code par la recherche à la mise en œuvre de l' FormsAuthenticationModule dans le réflecteur. Mon application est différente pour le haut- FormsAuthenticationModule en ce qu'elle ne veut pas faire quelque chose si vous répondez avec un 401 - pas de redirection vers la page de connexion. Je suppose que si cela devient une exigence, je peux mettre un élément dans le contexte de désactiver l'auto-réorienter ou de quelque chose.

11voto

Luke Sampson Points 3359

Je ne sais pas si cela fonctionnera pour tout le monde, mais dans IIS7 vous pouvez appeler de Réponse.Fin() après que vous avez mis le code du statut et de la description. De cette façon,#&$^#@*! FormsAuthenticationModule de ne pas faire une redirection.

public void ProcessRequest(HttpContext context) {
    Response.StatusCode = 401;
    Response.StatusDescription = "Authentication required";
    Response.End();
}

8voto

Tyler Forsythe Points 151

Pour construire sur zacharydl de réponse légèrement, je l'utilise pour résoudre mes malheurs. À chaque requête, au début, si c'est de l'AJAX, de supprimer immédiatement le comportement.

protected void Application_BeginRequest()
{
    HttpRequestBase request = new HttpRequestWrapper(Context.Request);
    if (request.IsAjaxRequest())
    {
        Context.Response.SuppressFormsAuthenticationRedirect = true;
    }
}

4voto

Amila Points 44

ce que vous avez trouvé est correct sur les formes d'authentification de l'interception de l'autoroute 401 et de faire une redirection mais nous pouvons également le faire pour renverser cette tendance.

Fondamentalement, ce que vous avez besoin est un module http intercepter la redirection 302 vers la page de connexion et l'inverse pour un 401.

Les étapes à faire ce qui est expliqué ici

Le lien donné est à propos d'un service WCF, mais il est le même dans toutes les formes auth scénarios.

Comme expliqué dans le lien ci-dessus vous devez effacer les en-têtes http en tant que bien, mais n'oubliez pas de mettre le témoin en-tête en arrière pour la réponse si la réponse initiale (c'est à dire avant l'interception) contenait des cookies.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X