2015-12-02 2 views
12

Ich habe diese seit Stunden geschlagen und ich bin ratlos. Ich mache eine Ajax-Post-Anfrage an einen MVC 5-Controller, um einen bestimmten vordefinierten "Super" -Benutzer automatisch einzuloggen. In der Controller-Methode versuche ich, den HttpContext.Current.User programmatisch zu setzen und authentifizieren, so dass der Super-Benutzer den Prozess der manuellen Anmeldung überspringen kann. Der Konsens darüber scheint hier zu sein, die ich implementiert habe:.net Formularauthentifizierung - manuelle Einstellung von HttpContext.Current.User funktioniert nicht in benutzerdefinierten AuthorizeAttribute

setting HttpContext.Current.User

Dies scheint zu funktionieren, bis ich versuche, andere Controller-Methoden mit einem benutzerdefinierten AuthorizeAttribute anzuzeigen.

Controller-Methode:

[HttpPost] 
[AllowAnonymous] 
public ActionResult Login(string username) 
{ 
    string password = ConfigurationManager.AppSettings["Pass"]; 

    User user = service.Login(username, password); 

    var name = FormsAuthentication.FormsCookieName; 
    var cookie = Response.Cookies[name]; 
    if (cookie != null) 
    { 
     var ticket = FormsAuthentication.Decrypt(cookie.Value); 
     if (ticket != null && !ticket.Expired) 
     { 
      string[] roles = (ticket.UserData as string ?? "").Split(','); 
      System.Web.HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), roles); 
     } 
    } 

    //...processing result 

    return Json(result); 
} 

Die service.Login Methode über das Cookie erstellt:

FormsAuthentication.SetAuthCookie(cookieValue, false); 

Obwohl ich die Einstellung der Benutzer, die eine Identität hat und IsAuthenticated ist wahr, die filterContext .HttpContext.User ist nicht derselbe Benutzer. Es ist im Wesentlichen leer, als ob es nie zugewiesen wurde und nicht authentifiziert ist.

public override void OnAuthorization(AuthorizationContext filterContext) 
{ 
    string[] userDetails = filterContext.HttpContext.User.Identity.Name.Split(char.Parse("|")); 
} 

Die nächstgelegene Post ich finden konnte ist hier: IsAuthenticated works on browser - but not with Air client!

jedoch das Update für das war bereits für mich:

<authentication mode="Forms"> 
    <forms cookieless="UseCookies" timeout="60" loginUrl="~/Account/Login" /> 
</authentication> 

Was ich die AuthorizationContext machen bin fehlt. Benutzer stimmen die HttpContext.Current.User, die ich im Controller authentifizieren?

UPDATE:

Ich weiß, ich brauche eine Umleitung des Cookies richtig zu setzen, ich bin in der Lage einfach nicht, dass die Arbeit der Ferne zu machen, über einen Ajax-Aufruf. So sieht das Skript in Site A aus, wenn die Controller-Methode auf Site B ausgeführt wird. Diese Weiterleitung legt die Sitzung nicht fest. Es ist immer noch nicht vorhanden, wenn der Benutzer bei der nächsten Controller-Methode authentifiziert wird. Es leitet mich nur zurück zur Login-Ansicht.

function remoteLogin(id) { 
    $.ajax({ 
     url: "/MyController/RemoteLogin", 
     type: "POST", 
     dataType: "json", 
     data: { "id": id } 
    }).done(function (data) { 
     if (data) { 
      if (data.user) { 
       var user = data.user; 
       $.ajax({ 
        url: "http://siteB.xyz/Account/Login", 
        type: "POST", 
        dataType: "json", 
        data: { "username": user.username, "password": user.password } 
       }).done(function (data) { 
        if (data) { 
         window.location.href = "http://siteB.xyz/Next" 
        } else { 
         alert("Fail."); 
        } 
       }).fail(function (data) { 
        alert("Fail."); 
       }); 
      } else { 
       alert("Fail."); 
      } 
     } 
    }).fail(function (data) { 
     alert("Fail."); 
    }); 
} 

Antwort

3

Das Problem, das Sie haben, ist an dieser Stelle Sie nur das Authentifizierungscookie Einstellung, die IPrincipal, die innerhalb des Formularauthentifizierungsmodul erstellt wird, wird nicht passieren, bis es eine neue Anforderung ist - so an diesem Punkt die Httpcontext . Benutzer ist in einem seltsamen Zustand. Sobald die Weiterleitung erfolgt, wird der Cookie gelesen, bevor die Seite erreicht wird und das korrekte Benutzerobjekt erstellt wurde, da es sich um eine neue Anfrage des Browsers handelt.

Cookies werden nur im Browser gesetzt, nachdem eine Anfrage abgeschlossen wurde.

+0

Das ist, was ich selbst gefunden habe, schau mich um - was ich suche ist eine Möglichkeit, dies im Zusammenhang mit dem zu tun, was ich versuche - ein Remote-Login. Zum Beispiel macht das Setzen des "location.href" beim Erfolg in meinem Skript keinen Unterschied. Ich brauche einen Weg, um das zu tun, was du im Entferntesten durch einen Ajax-Anruf beschreibst. –

+0

Bestätigt! Was ich getan habe (und es ist fraglich sicher), ist ein Cookie mit dem Benutzernamen/Passwort auf der Seite von App A zu schreiben und dann ein neues Fenster aus dem Skript zu öffnen, wenn der Ajax-Anruf erfolgreich war. In App B lese und zerstöre ich das temporäre Cookie, führe die Anmeldung durch und leite dann zur authentifizierten Ansicht um. Es scheint alles zu funktionieren. Wird später mein OP mit Details aktualisieren. –

2

Das Problem hängt davon ab, wo der Aktionscode relativ zur Pipeline für die Anforderungsverarbeitung ausgeführt wird. Ihr Code wird im Schritt ProcessRequest ausgeführt (siehe unten).

Die HttpContext.Current.User wird erwartet, dass durch die AuthenticateRequest Ereignishandler festgelegt werden. FormsAuthenticationModule kümmert sich darum, die Anforderung zu drehen.Cookies 'FormsAuthenticationCookie zurück in eine FormsAuthenticationTicket und dann in eine IPrincipal. Das Haupt wird als Request.CurrentUser gesetzt und ich glaube, Thread.CurrentPrincipal

Das am AuthenticateRequest Schritt getan werden muss, da die Cache-Anforderung durch den Benutzer variieren kann (ResolveRequestCache) und Sitzungszustand immer tut (AcquireRequestState). Auch der AuthorizeRequest Schritt macht über Entscheidungen, ob der Benutzer Haupt gesetzt in dem AuthenticateRequest Schritt hat die Erlaubnis, um durch den AuthorizeRequest Schritt erforderlich ist, ohne eine 401 oder immer 300-Ebene auf eine Anmeldeseite umleiten (und ich glaube, MVC und WebAPI Autorisierungsmechanismen arbeiten als Teil Process)

  • Beginrequest
  • AuthenticateRequest (FormsAuthenticationModule)
  • Authori zeRequest (zB UrlAuthorizationModule)
  • ResolveRequestCache
  • MapRequestHandler
  • AcquireRequestState
  • PreRequestHandlerExecute
  • Process (Httphandler, Web Forms, MVC Controller-Aktionen leben hier)

Sie können versuchen, diese zu zwingen, durch Einstellung HttpContext.Current.UserundThread.CurrentPrincipal zu Ihrem IPrincipal, aber es gilt nur für Code, der nach diesem Punkt in der ProcessRequest Phase läuft ... wichtige Entscheidungen über Sitzungsstatus, Cache und Autorisierung wurden bereits getroffen.

Theoretisch könnte man etwas ähnliches implementieren, was Sie versuchen, indem er ein Httpmodule und deren Umsetzung in/vor AuthenticateRequest (oder global.asax) zu tun, aber Sie würden noch keinen Zugang zu höher haben Ebene MVC-Controller Konzepte, Sitzungsstatus usw. würden Sie in der Lage sein HttpContext.Request.QueryString, HttpContext.Request.Form zu inspizieren, und HttpContext.Request.Cookies, aber sonst nicht viel. Sie müßten die Benutzername aus dem Ajax-Aufruf aus der HTTP-Anforderung greifen, und entweder rufen FormsAuthentication.SetAuthCookie() oder erstellen Sie ein FormsAuthenticationTicket und FormsAuthenticationCookie selbst und stopfen das Cookie in dem Request.Cookies und Response.Cookies. Zu dem Zeitpunkt, zu dem Ihre Controller-Logik ausgeführt wird, bin ich mir ziemlich sicher, dass die Anfrage authentifiziert erscheint.

+0

@ scott732 - Wirklich schätzen die eingehende Antwort. Klingt nach einer komplizierteren Herangehensweise als ich, mit der ich schließlich gegangen bin. Das ist alles gut zu wissen, danke. –

Verwandte Themen