10

Mamy aplikację, która korzysta z członkostwa ASP.net w celu zapewnienia podstawowych mechanizmów logowania. Wszystko działa dobrze, ale ostatnio odkryliśmy, że jeśli spróbujesz przejść do strony logowania po zalogowaniu, nastąpi przekierowanie na stronę "Nieautoryzowane".Członkostwo ASP.NET Logowanie przekierowujące do nieautoryzowanego po zalogowaniu użytkownika

Przykładowy przepływ użytkownika.

Użytkownik przechodzi do zabezpieczonej strony (cała aplikacja wymaga zalogowania, jest tam nawet strona główna, którą można odwiedzić, po prostu przekierowuje bezpośrednio do logowania). To przekierowuje je do https://www.example.com/Account/Login.

Użytkownik loguje się i jest przekierowywany na stronę główną https://www.example.com/. Są one zalogowane i wszystko działa poprawnie.

użytkownik kliknie zakładkę, która okazuje się być ustawiona na https://www.example.com/Account/Login

użytkownik jest przekierowywany do rodzajowego Nieautoryzowany stronie.

mam atrybut <Authorize()> na moim AccountController ale atrybut <AllowAnonymous()> sprawie działań „login”, który jak widzieliśmy wcześniej, działa dobrze, kiedy nie jesteś zalogowany, ale kiedy jesteś wydaje się w sposób trochę pomieszania.

AccountController

<Authorize()> _ 
Public Class AccountController 
'''other functions go here''' 

<AllowAnonymous()> _ 
Public Function Login(ByVal returnUrl As String) As ActionResult 
    ViewData("ReturnUrl") = returnUrl 
    Return View() 
End Function 

filtr AuthorizeRedirect

<AttributeUsage(AttributeTargets.[Class] Or AttributeTargets.Method)> _ 
Public Class AuthorizeRedirect 
    Inherits AuthorizeAttribute 
    Private Const IS_AUTHORIZED As String = "isAuthorized" 

    Public RedirectUrl As String = "~/Home/Unauthorized" 

    Protected Overrides Function AuthorizeCore(httpContext As System.Web.HttpContextBase) As Boolean 
     Dim isAuthorized As Boolean = MyBase.AuthorizeCore(httpContext) 

     httpContext.Items.Add(IS_AUTHORIZED, isAuthorized) 

     Return isAuthorized 
    End Function 

    Public Overrides Sub OnAuthorization(filterContext As AuthorizationContext) 
     MyBase.OnAuthorization(filterContext) 

     Dim isAuthorized = If(filterContext.HttpContext.Items(IS_AUTHORIZED) IsNot Nothing, Convert.ToBoolean(filterContext.HttpContext.Items(IS_AUTHORIZED)), False) 

     If Not isAuthorized AndAlso filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated Then 
      filterContext.RequestContext.HttpContext.Response.Redirect(RedirectUrl) 
     End If 
    End Sub 
End Class 

Widząc to wszystko myślałem, że najprostszym rozwiązaniem byłoby sprawdzić, czy użytkownik jest już zalogowany na mój login działania i przekierowanie je same, coś takiego.

<AllowAnonymous()> _ 
Public Function Login(ByVal returnUrl As String) As ActionResult 
    If User.Identity.IsAuthenticated() Then 
     Return RedirectToAction("Index", "Home") 
    End If 
    ViewData("ReturnUrl") = returnUrl 
    Return View() 
End Function 

Ale AuthorizeFilter zawsze skacze w pierwszej okazji, co jest zrozumiałe, ale nie mogę dość dowiedzieć się ostatni brakujący kawałek. Chcę tylko, aby nie wyświetlał się komunikat "Nie masz uprawnień do oglądania tej strony", jeśli użytkownik wejdzie na ekran logowania po zalogowaniu, a raczej przekieruje go na stronę główną. czego mi brakuje?


Edytuj, aby dokonać rzeczy nieco jaśniejsze

Kiedy już zalogowany, idę do /Account/Login. To 302 przekierowuje mnie do /Home/Unauthorized (moja strona niestandardowa). Jednak nadal jestem zalogowany. Żąda

Network

Network request to Login page, which 302 redirects to Unauthorized

Nieuprawnione strona. Zauważ, że podświetlone żółte sekcje pokazują, że wciąż jestem zalogowany. Pojawia się tylko wtedy, gdy jesteś zalogowany. Kiedy się nie zalogujesz, nie dostajesz tego.

Unauthorized page

Problem wydaje się być to, że aplikacja nie wie, co zrobić, gdy jestem już zalogowany i próbuje przejść do strony, która ma atrybut [AllowAnonymous] na nim. Jeśli cokolwiek, to zachowanie, które tu widzę, jest lepsze od tego, że ponownie daje mi stronę logowania, ponieważ byłoby to mylące, ale nadal nie jest idealne.


Edycja 2 - Krocząc przez linię kodu przez linię

Oto wyniki wstępnej przez linię kodu po linii.

Page /Account/Login zalogowaniu się.

Pierwszy punkt przerwania w OnAuthorization sub w AuthorizeRedirect filtra.

Public Overrides Sub OnAuthorization(filterContext As AuthorizationContext) 
    MyBase.OnAuthorization(filterContext) 

    Dim isAuthorized = If(filterContext.HttpContext.Items(IS_AUTHORIZED) IsNot Nothing, Convert.ToBoolean(filterContext.HttpContext.Items(IS_AUTHORIZED)), False) 

    If Not isAuthorized AndAlso filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated Then 
     filterContext.RequestContext.HttpContext.Response.Redirect(RedirectUrl) 
    End If 
End Sub 

Linia rozpoczynająca się od Dim isAuthorized zwraca Fałsz. filterContext.HttpContext.Items(IS_AUTHORIZED) jest niczym (nie ma na liście pozycji).

Oznacza to, że następna instrukcja If ma wartość True (Nie jest autoryzowana iAlso ... IsAuthenticated), co powoduje przekierowanie do RedirectUrl.

Po tym zdarzeniu wydaje się, że cofa się o te same czynności, z tą różnicą, że wartość ta jest równa false, co oznacza, że ​​przekierowanie nie występuje, chociaż domyślam się, że jest to po prostu ładowanie i uruchamianie strony "Nieautoryzowane". ten sam kod ponownie.

Podjęto próbę dodania następującego bloku na górę funkcji Login urządzenia AccountController.

If User.Identity.IsAuthenticated() Then 
     Return RedirectToAction("Index", "Home") 
    End If 

Ale, oczywiście, ponieważ filtr jest prowadzony przed wystąpić działania tego kodu nie jest trafiony, dopóki po to już przekierowanie mnie do Unauthorized (zweryfikowane przez przechodzeniu).

+0

Gdzie jest stosowane "AuthorizeRedirect"? –

+0

Nie mam teraz dostępu do kodu, ale jestem pewien, że jest skonfigurowany w standardowym FilterConfig z czymś takim jak "filters.add (Authorizeredirect)" –

+0

wydaje się, że użytkownik jest nieautoryzowany. Czy to prawda? czy możesz trafić/home/index po przekierowaniu do nieautoryzowanego? –

Odpowiedz

2

Klasa bazowa AuthorizationAttribute ma ten kod w metodzie OnAuthorization:

bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true) 
         || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true); 

if (skipAuthorization) 
{ 
    return; 
} 

if (AuthorizeCore(filterContext.HttpContext)) 
// ... 

jako takie, jeśli akcja kontroler ma AllowAnonymousAttribute zdefiniowany na nim, Twoja metoda AuthorizeCore nie zostanie wywołana.

Z tego powodu filterContext.HttpContext.Items(IS_AUTHORIZED) nigdy nie zostaną ustawione.

Możesz po prostu skopiować kod z here, aby zaimplementować OnAuthorization bez wywoływania klasy bazowej. W ten sposób możesz poradzić sobie z buforowaniem, w którym zawsze chcesz.

Nawiasem mówiąc, miałem wrażenie, że jeśli autoryzacja się nie powiedzie, to późniejszy proces w potoku żądania przebiegł przekierowanie do strony logowania. Dlatego podstawowa implementacja OnAuthorization ustawia filterContext.Result na nową instancję HttpUnauthorizedResult. Więc nie jest całkowicie jasne, dlaczego przesuwasz OnAuthorization i robisz przekierowanie w pierwszej kolejności.Jeśli chcesz mieć jakiś niestandardowy kod autoryzacji, wystarczy zwrócić true lub false z AuthorizeCore powinno wystarczyć.