2016-08-19 10 views
8

Na naszej stronie MVC zabezpieczamy nasze punkty końcowe za pomocą atrybutu Authorize, jednak chciałbym przekierować użytkownika do ekranu logowania, kiedy to nastąpi. Moje pierwsze rozwiązanie było przekierować na Application_EndRequest w Global.asax.cs:Jak mogę przekierować na mój ekran logowania po nieautoryzowanym otrzymaniu kodu statusu 401 w MVC?

protected void Application_EndRequest(object sender, EventArgs e) 
    { 
     if (Response.StatusCode == (int) HttpStatusCode.Unauthorized) 
     { 
      Response.ClearContent(); 
      Response.Redirect("/Account/Login"); 
     } 
    } 

Problemem jest to, że niektóre z naszych poglądów są ładowane przez AJAX, w tym przypadku nie chcemy, aby wyświetlić ekran logowania w dynamicznie załadowanego div (dzieje się tak na przykład po naciśnięciu przycisku Wstecz po wylogowaniu). Byłoby lepiej, gdyby żądanie nadal zwracało ekran logowania, ale z 401 nieautoryzowanym kodem statusu, abyśmy mogli wykryć to zdarzenie. Oczywiście to nie zadziała z tym podejściem, ponieważ przekierowanie opiera się na kodzie statusu 302.

Zamiast tego wolałbym "wstawić" zawartość ekranu logowania w numerze Application_EndRequest z kodem stanu 401. Tak więc, zamiast Response.Redirect, próbowałem to:

  ... 
      Response.ClearContent(); 
      Server.TransferRequest("~/Account/Login"); 
      Response.StatusCode = (int) HttpStatusCode.Unauthorized; 
      ... 

Przekierowanie działa ładnie, ale ponieważ wykonuje nową prośbę, nie mogę ustawić kod stanu w ten sposób, a ja dostaję 200. Nadal nie nadaje się do wykrycia nieautoryzowanego żądania.

Próbowałem również:

  ... 
      Response.ClearContent(); 
      Server.Transfer("~/Account/Login"); 
      Response.StatusCode = (int) HttpStatusCode.Unauthorized; 
      ... 

Ale otrzymuję wyjątek "Błąd podczas wykonywania żądania dla dzieci/Konta/login".

Próbowałem również:

  ... 
      Response.ClearContent(); 
      HttpContext.Current.RewritePath("~/Account/Login"); 
      Response.StatusCode = (int) HttpStatusCode.Unauthorized; 
      Response.End(); 
      ... 

Ale to zgłasza wyjątek "Temat był przerwany". Nie jestem pewien, czy Response.End() jest konieczne, ale bez niego, po prostu uzyskać standardowy błąd IIS 401.

Jak mogę zwrócić zawartość mojego ekranu logowania, ale z kodem statusu 401?

+0

Spróbuj użyć niestandardowej obsługi błędów za pomocą zestawu 401, aby zwrócić widok logowania. –

Odpowiedz

4

Próbowałem kilka różnych metod, z których wszystkie miały swoje podstępne problemy. Nie wiesz, w jaki sposób rozwiązanie jest ustawiony, ale jeśli trzeba wykonać przelew można wykorzystać następujące:

niestandardowy AuthorizeAttribute

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     filterContext.RequestContext.HttpContext.Server.TransferRequest("/Account/Login/?NOT_AUTHORISED=TRUE", false); 
    } 
} 

Trzeba przekazać wiadomość do kolejnego wniosku, używając ciągu kwerendy wydawał się Zrób sztuczkę. Chociaż musisz pamiętać, że każdy może ustawić parametr QS.

Kod ustawić status

protected void Application_EndRequest(object sender, EventArgs e) 
{ 
    if (Request["NOT_AUTHORISED"] == "TRUE") 
    { 
     Response.StatusCode = (int) HttpStatusCode.Unauthorized; 
    } 
} 

Demo

Nie ma przekierowania i kod HTTP status jest ustawiony na 401.

enter image description here

8

Wysyłanie 401 i ViewObject lub RedirectObject nie jest tak, jak zaprojektowano MVC Framework do pracy: - kilka postów sprytnie pokazało, że powrót 401 z widokiem z filtrem autoryzacji.

mogę określić MVC Framework, ale to nie jest jeszcze preferowana sposobem użycia HTTP protokół.

  • Przy przekierowaniu w MVC aplikacji utworzeniu RedirectResult
  • Gdy MVC powraca aplikacyjne z wezwaniem do View() metoda kontrolera, o ViewResult jest tworzone

To czy Przekierowanie lub Zobacz ostatecznie osiągnie przeglądarkę klienta albo,

  • HTTP Return Code z - Sukces zostaną zwrócone

Or

  • HTTP Return Code z - Przekierowanie zostanie zwrócony

Powodem tej konwencji jest to, że serwer "obsługuje" przekierowanie. Jeśli użytkownik nie jest autoryzowany, serwer przekieruje użytkownika na stronę logowania.

Simlarly w AJAX lub asynchronicznych żądań HTTP, tak długo, jak jest zwrócony HTML Zobacz, żądanie HTTP jest uważane za sukces. Przekierowanie (302) nie jest zwracane dla żądań asynchronicznych.


Wysyłanie kodów błędów do klienta:

Jeśli chcesz zwrócić 401nieautoryzowanego do klienta, które zwykle oznacza, że ​​chcesz do klienta „Handle” nieuprawnionego wniosek przejście do widoku logowania lub błędu.

$.ajax({ 
    url: loginURL, 
    data: $("#form").serialize(), 
    type: "POST", 
    dataType: "html" 
}) 
.success(function (result, status) { 
      /*additional logic*/ 
}) 
.error(function (xhr, status) { 
    if (xhr.status == 401) 
    { 
     window.location = unauthorizedUrl; //redirect to unauthorized url 
    } 
}); 

Co zrobić, jeśli chcesz przekierować do strony logowania strona i pokazuje błąd

Twoje pytanie sprawia, że ​​największy sens, jeśli chcesz przekierować do logowania strony i wyświetla błąd

Bad Login Attempt

Następnie konwencją jest dodanie komunikatu o błędzie do Viewbag lub błędów ModelState

takich jak:

 var user = await signInManager.UserManager.FindByNameAsync(model.UserName); 

       ModelState.AddModelError("", "Invalid username or password."); 
       return View(model); 

w widoku, aby mieć kod, który wygląda na błąd:

ValidationSummary będzie pickup błąd modelu

  @Html.ValidationSummary(true) 

Ten konkretny przykład nieprawidłowej próby logowania nie odpowiada dokładnie przykładowi.

Nie mogę znaleźć obrazu dla użytkownika przekierowanego, ponieważ nie byli upoważnieni, ale w tym przypadku logika jest podobna. Błąd Msg może być wypełniana z QueryString, Viewbag itp

+0

W odpowiedzi, którą podałem poniżej, zwracam ViewObject i 401 Status Code. – timkly

+0

@timkly, masz rację. Powinienem edytować mój post i przyznać, że jest to możliwe. –

6

Można by idealnie chcesz użyć niestandardowego AuthorizeAtrribute a następnie podłączyć do metody HandleUnauthorizedRequest i od tego, powrót widok do strony logowania przez ustawienie kontroler i widok, aby wywołać w AuthorizationContext.

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
     { 
      filterContext.RouteData.Values["controller"] = "home"; 
      filterContext.RouteData.Values["action"] = "login"; 

      filterContext.Result = new ViewResult(); 
      filterContext.HttpContext.Response.Clear(); 
      filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 
      filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
      filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; 
     } 
    } 
} 

uwaga: Sztuką jest to, aby upewnić się ustawić następującą wartość true, aby uniknąć uwierzytelniania formularzy przejmując odpowiedzi kiedy już ustawić status 401.

HttpContext.Response.SuppressFormsAuthenticationRedirect = true;