W ASP.NET MVC możesz oznaczyć metodę kontrolera za pomocą AuthorizeAttribute
:
[Authorize(Roles = "CanDeleteTags")]
public void Delete(string tagName)
{
// ...
}
Oznacza to, że jeśli aktualnie zalogowany użytkownik nie ma roli „CanDeleteTags”, metoda kontrolera nigdy nie zostanie wywołana.
Niestety w przypadku awarii AuthorizeAttribute
zwraca HttpUnauthorizedResult
, który zawsze zwraca kod stanu HTTP 401. Powoduje to przekierowanie na stronę logowania.
Jeśli użytkownik nie jest zalogowany, ma to sens. Jeśli jednak użytkownik jest już zalogowany, ale nie ma wymaganej roli, mylące jest wysyłanie go z powrotem na stronę logowania.
Wygląda na to, że AuthorizeAttribute
łączy uwierzytelnianie i autoryzację.
To wydaje się trochę przeoczone w ASP.NET MVC, czy coś mi brakuje?
Musiałem przygotować coś, DemandRoleAttribute
co oddziela te dwa elementy. Gdy użytkownik nie jest uwierzytelniony, zwraca HTTP 401, wysyłając go na stronę logowania. Gdy użytkownik jest zalogowany, ale nie ma wymaganej roli, tworzy NotAuthorizedResult
zamiast niego. Obecnie przekierowuje to na stronę błędu.
Z pewnością nie musiałem tego robić?
źródło
Odpowiedzi:
Gdy został opracowany po raz pierwszy, System.Web.Mvc.AuthorizeAttribute działał dobrze - starsze wersje specyfikacji HTTP używały kodu stanu 401 zarówno dla „nieautoryzowanego”, jak i „nieuwierzytelnionego”.
Z oryginalnej specyfikacji:
W rzeczywistości widać zamieszanie - używa słowa „autoryzacja”, gdy oznacza „uwierzytelnianie”. Jednak w codziennej praktyce bardziej sensowne jest zwracanie 403 Zabronione, gdy użytkownik jest uwierzytelniony, ale nie autoryzowany. Jest mało prawdopodobne, że użytkownik będzie miał drugi zestaw poświadczeń, które dadzą mu dostęp - złe wrażenia użytkownika dookoła.
Zastanów się nad większością systemów operacyjnych - gdy próbujesz odczytać plik, do którego nie masz uprawnień, nie wyświetla się ekran logowania!
Na szczęście specyfikacje HTTP zostały zaktualizowane (czerwiec 2014 r.) W celu usunięcia niejasności.
Z „Hyper Text Transport Protocol (HTTP / 1.1): Uwierzytelnianie” (RFC 7235):
Z „Hypertext Transfer Protocol (HTTP / 1.1): Semantyka i treść” (RFC 7231):
Co ciekawe, w momencie wydania programu ASP.NET MVC 1 zachowanie funkcji AuthorizeAttribute było prawidłowe. Teraz zachowanie jest nieprawidłowe - poprawiono specyfikację HTTP / 1.1.
Zamiast próby zmiany przekierowań strony logowania ASP.NET, łatwiej jest po prostu naprawić problem u źródła. Możesz utworzyć nowy atrybut o tej samej nazwie (
AuthorizeAttribute
) w domyślnej przestrzeni nazw swojej witryny (jest to bardzo ważne), a następnie kompilator automatycznie wybierze ją zamiast standardowej MVC. Oczywiście zawsze możesz nadać atrybutowi nową nazwę, jeśli wolisz takie podejście.źródło
filterContext.HttpContext.User.Identity.IsAuthenticated
, możesz po prostu sprawdzićfilterContext.HttpContext.Request.IsAuthenticated
, która zawiera wbudowane czeki zerowe. Zobacz stackoverflow.com/questions/1379566/…Dodaj to do swojej funkcji logowania Page_Load:
Gdy użytkownik zostaje tam przekierowany, ale jest już zalogowany, wyświetla nieautoryzowaną stronę. Jeśli nie są zalogowani, przechodzi przez i wyświetla stronę logowania.
źródło
if (User.Identity != null && User.Identity.IsAuthenticated) return RedirectToRoute("Unauthorized");
którym Nieautoryzowane to zdefiniowana nazwa trasy.Zawsze myślałem, że to ma sens. Jeśli jesteś zalogowany i próbujesz wejść na stronę, która wymaga roli, której nie masz, zostaniesz przekierowany do ekranu logowania z prośbą o zalogowanie się z użytkownikiem, który ma tę rolę.
Możesz dodać logikę do strony logowania, która sprawdza, czy użytkownik jest już uwierzytelniony. Możesz dodać przyjazną wiadomość, która wyjaśnia, dlaczego zostali tam ponownie sparaliżowani.
źródło
Niestety masz do czynienia z domyślnym zachowaniem uwierzytelniania formularzy ASP.NET. Jest obejście (nie próbowałem tego) omówione tutaj:
http://www.codeproject.com/KB/aspnet/Custon401Page.aspx
(To nie jest specyficzne dla MVC)
Myślę, że w większości przypadków najlepszym rozwiązaniem jest ograniczenie dostępu do nieautoryzowanych zasobów, zanim użytkownik spróbuje się tam dostać. Przez usunięcie / wyszarzenie linku lub przycisku, który może doprowadzić ich do tej nieautoryzowanej strony.
Prawdopodobnie byłoby miło mieć dodatkowy parametr w atrybucie, aby określić, gdzie przekierować nieautoryzowanego użytkownika. Ale w międzyczasie patrzę na AuthorizeAttribute jako sieć bezpieczeństwa.
źródło
Wypróbuj to w module obsługi Application_EndRequest pliku Global.ascx
źródło
Jeśli używasz aspnetcore 2.0, użyj tego:
źródło
W moim przypadku problemem był „specyfikacja HTTP użyła kodu stanu 401 zarówno dla„ nieautoryzowanego ”, jak i„ nieuwierzytelnionego ”. Jak powiedział ShadowChaser.
To rozwiązanie działa dla mnie:
źródło