2015-12-02 11 views
12

Ho colpito questo per ore e sono perplesso. Sto effettuando una richiesta di posta ajax su un controller MVC 5 nel tentativo di accedere automaticamente a uno specifico utente "super" predefinito. Nel metodo controller, sto provando a impostare HttpContext.Current.User al livello di programmazione e autenticarlo, in modo che l'utente super possa ignorare il processo di accesso manuale. Il consenso su questo sembra essere qui, che ho implementato:.net Autenticazione moduli - impostazione manuale HttpContext.Current.User non funziona in personalizzato AuthorizeAttribute

setting HttpContext.Current.User

Questo sembra funzionare finché non provo a visualizzare altri metodi di controller con un AuthorizeAttribute personalizzato. Metodo

Controller:

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

Il metodo service.Login precedente crea il cookie:

FormsAuthentication.SetAuthCookie(cookieValue, false); 

se sto Impostazioni dell'utente, che ha un'identità e IsAuthenticated è vero, il filterContext .HttpContext.User di seguito non è lo stesso utente. È essenzialmente vuoto come se non fosse mai stato assegnato e non sia autenticato.

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

Il post più vicina che ho trovato è qui: IsAuthenticated works on browser - but not with Air client!

Tuttavia, la correzione per che era già in atto per me:

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

Che cosa mi manca per fare l'AuthorizationContext. L'utente corrisponde a HttpContext.Current.User che sto autenticando nel controller?

UPDATE:

mi rendo conto che ho bisogno di un reindirizzamento per impostare correttamente il cookie, solo che non sono in grado di fare quel lavoro da remoto, tramite una chiamata AJAX. Ecco come appare lo script nel sito A, quando si esegue il metodo del controller sul sito B. Questo reindirizzamento non imposta la sessione. Non è ancora presente quando si autentica l'utente sul prossimo metodo del controller. Mi ha appena reindirizzato alla vista di accesso.

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

risposta

3

Il problema che hai è a questo punto si sta solo impostando il cookie di autenticazione, l'IPrincipal che viene creato all'interno del modulo di autenticazione form non accadrà finché non ci sarà una nuova richiesta - così a quel punto il HttpContext . L'utente è in uno stato strano. Una volta che il reindirizzamento avviene, poiché si tratta di una nuova richiesta dal browser, il cookie verrà letto prima che venga raggiunta la pagina e creato l'oggetto utente corretto.

I cookie sono impostati sul browser solo al termine di una richiesta.

+0

Questo è quello che mi sono trovato, guardandomi intorno: quello che sto cercando è un modo per farlo nel contesto di ciò che sto tentando: un accesso remoto. Ad esempio, l'impostazione "location.href" in caso di successo, nel mio script, non fa alcuna differenza. Ho bisogno di un modo per fare ciò che stai descrivendo, da remoto, attraverso una chiamata ajax. –

+0

Confermato! Quello che ho fatto (ed è discutibile-sicuro), è scrivere un cookie con il nome utente/password sul lato App A, quindi aprire una nuova finestra dallo script, in caso di successo della chiamata ajax. Nell'App B, leggo e distruggo il cookie temporaneo, eseguo il login, quindi reindirizzo alla vista autenticata. Sembra tutto funzionare. Aggiornerà il mio OP con i dettagli, in seguito. –

2

Il problema ha a che fare con il codice di azione in esecuzione rispetto alla pipeline di elaborazione delle richieste. Il tuo codice è in esecuzione nel passaggio ProcessRequest (vedi sotto).

Il HttpContext.Current.User dovrebbe essere impostata dal gestore di eventi AuthenticateRequest. FormsAuthenticationModule si occupa di questo, trasformando la richiesta .Cookies 'FormsAuthenticationCookie di nuovo in un FormsAuthenticationTicket e poi in un IPrincipal. Quella principale viene impostato come Request.CurrentUser e credo Thread.CurrentPrincipal

Questo deve essere fatto al passo AuthenticateRequest perché la cache richiesta può variare da utente (ResolveRequestCache) e lo stato di sessione sempre (AcquireRequestState). Inoltre, il passo AuthorizeRequest prende decisioni sul fatto che il principale utente impostato nel passo AuthenticateRequest ha autorizzato a passare attraverso il passo AuthorizeRequest senza ottenere un livello di 300 401 o reindirizzare ad una pagina di login (e credo MVC e meccanismi di autorizzazione di WebAPI funzionano come parte di ProcessRequest)

  • BeginRequest
  • AuthenticateRequest (FormsAuthenticationModule)
  • Authori zeRequest (ad esempio, UrlAuthorizationModule)
  • ResolveRequestCache
  • MapRequestHandler
  • AcquireRequestState
  • PreRequestHandlerExecute
  • ProcessRequest (HttpHandler, Web Forms, azioni di controllo MVC vivono qui)

si può provare a forzare questo impostando HttpContext.Current.UsereThread.CurrentPrincipal al IPrincipal, ma si applica solo al codice in esecuzione dopo quel punto nella fase ProcessRequest ... sono già state prese decisioni importanti sullo stato della sessione, sulla cache e sull'autorizzazione.

In teoria, si potrebbe implementare qualcosa di simile a quello che stai cercando di fare scrivendo un HttpModule e la sua attuazione in/prima AuthenticateRequest (o global.asax), ma non si hanno ancora accesso a più elevato livello di concetti del controller MVC, lo stato della sessione, ecc devi essere in grado di ispezionare HttpContext.Request.QueryString, HttpContext.Request.Form, e HttpContext.Request.Cookies, ma non molto altro. Dovreste prendere il nome utente dalla chiamata AJAX fuori della richiesta HTTP, e neanche chiamare FormsAuthentication.SetAuthCookie() o si crea una FormsAuthenticationTicket e FormsAuthenticationCookie se stessi e roba il cookie nelle Request.Cookies e Response.Cookies. Nel momento in cui viene eseguita la logica del controller, sono abbastanza sicuro che la richiesta sembrerebbe autenticata.

+0

@ scott732 - Apprezzo davvero la risposta approfondita. Sembra un approccio più complicato di quello con cui finalmente sono andato. Questo è tutto bene sapere, grazie. –

Problemi correlati