2015-12-02 27 views
12

Uderzam w tę stronę od wielu godzin i jestem zdziwiony. Tworzę żądanie ajax ajax do kontrolera MVC 5, próbując automatycznie zalogować określonego, zdefiniowanego "super" użytkownika. W metodzie sterownika próbuję programowo ustawić HttpContext.Current.User i uwierzytelnić, aby superużytkownik mógł pominąć proces ręcznego logowania. Konsensus w tej sprawie wydaje się być tutaj, który zaimplementowałem:. Uwierzytelnianie za pomocą formularzy .net - ręczne ustawianie HttpContext.Current.User nie działa w niestandardowy AuthorizeAttribute

setting HttpContext.Current.User

Wydaje się to działać, dopóki nie spróbuję wyświetlić żadnych innych metod kontrolera z niestandardowym AuthorizeAttribute. Metoda

Kontroler:

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

Sposób service.Login powyżej tworzy plik cookie:

FormsAuthentication.SetAuthCookie(cookieValue, false); 

choć jestem ustawienie użytkownika, który ma swoją tożsamość i IsAuthenticated jest prawdziwe, filterContext .HttpContext.User poniżej nie jest tym samym użytkownikiem. Jest w zasadzie pusty, jakby nigdy nie był przypisany i nie jest uwierzytelniony.

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

Najbliższa poczta mogłem znaleźć tutaj: IsAuthenticated works on browser - but not with Air client!

Jednak poprawka na to było już na miejscu dla mnie:

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

Co mi brakuje, aby AuthorizationContext. Użytkownik pasuje do HttpContext.Current.User, który uwierzytelniam w kontrolerze?

UPDATE:

Zdaję sobie sprawę, że trzeba ustawić przekierowanie cookie prawidłowo, po prostu nie jestem w stanie wykonać tę pracę zdalnie, za pośrednictwem wywołania AJAX. Oto, jak wygląda skrypt w witrynie A podczas wykonywania metody kontrolera na stronie B. To przekierowanie nie ustawia sesji. Nadal nie jest obecny podczas uwierzytelniania użytkownika przy użyciu kolejnej metody kontrolera. Przekierowuje mnie z powrotem do widoku logowania.

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

Odpowiedz

3

Problem masz to w tym momencie jesteś tylko ustawienie cookie uwierzytelniania, że ​​dostaje się IPrincipal utworzony wewnątrz modułu uwierzytelniania formularzy nie nastąpi, dopóki nie jest nowy wniosek - tak w tym momencie HttpContext .User jest w dziwnym stanie. Po wykonaniu przekierowania, ponieważ jest to nowe żądanie przeglądarki, plik cookie zostanie odczytany, zanim strona zostanie osiągnięta i zostanie utworzony właściwy obiekt użytkownika.

Pliki cookie są ustawiane tylko w przeglądarce po zakończeniu żądania.

+0

To właśnie znalazłem się, rozglądając się - to, czego szukam, jest sposobem na zrobienie tego w kontekście tego, co próbuję - zdalnego logowania. Na przykład ustawienie "location.href" w przypadku sukcesu w moim skrypcie nie ma znaczenia. Potrzebuję sposobu, aby zrobić to, co opisujesz, zdalnie, przez wywołanie ajax. –

+0

Potwierdzone! To, co zrobiłem (i jest to wątpliwe), to napisanie pliku cookie z nazwą użytkownika/hasłem po stronie App A, a następnie otworzenie nowego okna ze skryptu, na sukces wywołania ajax. W aplikacji B czytam i niszczę tymczasowy plik cookie, wykonuję logowanie, a następnie przekierowuję do uwierzytelnionego widoku. Wszystko wydaje się działać. Zaktualizuje mój OP o szczegóły, później. –

2

Problem związany jest z tym, gdzie działa kod działania względem potoku przetwarzania żądania. Twój kod jest uruchomiony w kroku ProcessRequest (patrz poniżej).

The HttpContext.Current.User ma zostać ustawiony przez obsługi zdarzeń AuthenticateRequest. FormsAuthenticationModule zajmuje się tym, zamieniając prośbę .Pliki cookie 'FormularzeAuthenticationCookie z powrotem na FormularzeAuthenticationTicket, a następnie na IPrincipal. Że główny zostanie ustawiony jako Request.CurrentUser i wierzę Thread.CurrentPrincipal

To musi być zrobione w AuthenticateRequest kroku bo cache żądanie może się zmieniać przez użytkownika (ResolveRequestCache) i stanu sesji zawsze ma (AcquireRequestState). Również AuthorizeRequest krok podejmuje decyzje o tym, czy główny użytkownik ustawić w AuthenticateRequest kroku ma wymaganego pozwolenia, aby przejść przez AuthorizeRequest kroku bez uzyskania 401 lub 300-poziom przekierowanie na stronę logowania (i wierzę, MVC i mechanizmy autoryzacji WebAPI pracują jako część ProcessRequest)

  • BeginRequest
  • AuthenticateRequest (FormsAuthenticationModule)
  • Urzędów zeRequest (np UrlAuthorizationModule)
  • ResolveRequestCache
  • MapRequestHandler
  • AcquireRequestState
  • PreRequestHandlerExecute
  • ProcessRequest (HttpHandler, Web Forms, działania kontrolera MVC żyć tutaj)

Można próbować wymusić to ustawiając HttpContext.Current.UseriThread.CurrentPrincipal do twojego IPrincipal, ale będzie to miało zastosowanie tylko do kodu działającego po tym punkcie fazy ProcessRequest ... podjęto już ważne decyzje dotyczące stanu sesji, pamięci podręcznej i autoryzacji.

Teoretycznie można zaimplementować coś podobnego do tego, co próbujemy zrobić pisząc HttpModule i wdrożenie go w/przed AuthenticateRequest (lub Global.asax), ale nie ma jeszcze dostępu do wyższej poziom MVC koncepcje sterowniku, stan sesji itp Byłbyś w stanie sprawdzać HttpContext.Request.QueryString, HttpContext.Request.Form i HttpContext.Request.Cookies, ale niewiele więcej. Trzeba by chwycić nazwę użytkownika z AJAX wywołać żądania HTTP i albo zadzwonić FormsAuthentication.SetAuthCookie() lub utwórz FormsAuthenticationTicket i FormsAuthenticationCookie siebie i rzeczy cookie w Request.Cookies i Response.Cookies. Do czasu uruchomienia logiki kontrolera jestem pewien, że żądanie będzie wyglądało na uwierzytelnione.

+0

@ scott732 - Naprawdę doceniam szczegółową odpowiedź. Brzmi jak bardziej skomplikowane podejście niż to, z czym w końcu poszedłem. Wszystko to dobrze wiedzieć, dzięki. –