Muszę zrobić coś dość prostego: w mojej aplikacji ASP.NET MVC chcę ustawić niestandardową IIdentity / IPrincipal. Którykolwiek jest łatwiejszy / bardziej odpowiedni. Chcę rozszerzyć wartość domyślną, aby móc wywoływać coś takiego jak User.Identity.Id
i User.Identity.Role
. Nic szczególnego, tylko dodatkowe właściwości.
Przeczytałem mnóstwo artykułów i pytań, ale wydaje mi się, że robię to trudniejszym niż jest w rzeczywistości. Myślałem, że będzie łatwo. Jeśli użytkownik się zaloguje, chcę ustawić niestandardową IIdentity. Pomyślałem więc, że zaimplementuję Application_PostAuthenticateRequest
w moim global.asax. Jest to jednak wywoływane przy każdym żądaniu i nie chcę wykonywać wywołania do bazy danych przy każdym żądaniu, które zażądałoby wszystkich danych z bazy danych i umieściłoby niestandardowy obiekt IPrincipal. Wydaje się to również bardzo niepotrzebne, powolne i w niewłaściwym miejscu (wykonywanie tam wywołań bazy danych), ale mogę się mylić. Lub skąd jeszcze pochodzą te dane?
Pomyślałem więc, że za każdym razem, gdy użytkownik się loguje, mogę dodać niezbędne zmienne do mojej sesji, które dodam do niestandardowej IIdentity w module Application_PostAuthenticateRequest
obsługi zdarzeń. Jednak moje tam Context.Session
jest null
, więc nie jest to również właściwa droga.
Pracuję nad tym przez jeden dzień i czuję, że coś mi umknęło. Nie powinno to być zbyt trudne, prawda? Jestem również trochę zdezorientowany wszystkimi (częściowo) powiązanymi z tym rzeczami. MembershipProvider
, MembershipUser
, RoleProvider
, ProfileProvider
, IPrincipal
, IIdentity
, FormsAuthentication
.... ja jestem jedyną osobą, która wyszukuje wszystko to bardzo mylące?
Jeśli ktoś mógłby mi powiedzieć proste, eleganckie i wydajne rozwiązanie do przechowywania dodatkowych danych w IIdentity bez wszystkich dodatkowych problemów ... byłoby świetnie! Wiem, że na SO są podobne pytania, ale jeśli potrzebuję odpowiedzi, muszę to przeoczyć.
MemberShip...
,Principal
,Identity
. ASP.NET powinien uprościć, uprościć i maksymalnie dwa podejścia do uwierzytelniania.Odpowiedzi:
Oto jak to robię.
Zdecydowałem się użyć IPrincipal zamiast IIdentity, ponieważ oznacza to, że nie muszę implementować zarówno IIdentity, jak i IPrincipal.
Utwórz interfejs
CustomPrincipal
CustomPrincipalSerializeModel - do szeregowania niestandardowych informacji w polu danych użytkownika w obiekcie FormsAuthenticationTicket.
Metoda logowania - konfigurowanie pliku cookie z niestandardowymi informacjami
Global.asax.cs - Odczytywanie plików cookie i zastępowanie obiektu HttpContext.User odbywa się to przez przesłanianie PostAuthenticateRequest
Dostęp w widokach Razor
i w kodzie:
Myślę, że kod jest oczywisty. Jeśli nie, daj mi znać.
Dodatkowo, aby jeszcze łatwiej uzyskać dostęp, możesz utworzyć kontroler podstawowy i zastąpić zwrócony obiekt użytkownika (HttpContext.User):
a następnie dla każdego kontrolera:
co pozwoli ci uzyskać dostęp do niestandardowych pól w kodzie:
Ale to nie zadziała w widokach. W tym celu musisz utworzyć niestandardową implementację WebViewPage:
Ustaw jako domyślny typ strony w Views / web.config:
a w widokach możesz uzyskać do niego dostęp w następujący sposób:
źródło
Thread.CurrentPrincipal
atApplication_PostAuthenticateRequest
, aby działał, ponieważ nie zależy od niegoHttpContext.Current.User
FormsAuthentication.SignOut();
działa dla mnie dobrze.Nie mogę mówić bezpośrednio w przypadku ASP.NET MVC, ale w przypadku formularzy internetowych ASP.NET sztuczka polega na utworzeniu pliku
FormsAuthenticationTicket
i zaszyfrowaniu go w pliku cookie po uwierzytelnieniu użytkownika. W ten sposób wystarczy zadzwonić do bazy danych tylko raz (lub AD lub cokolwiek, czego używasz do wykonania uwierzytelnienia), a każde kolejne żądanie zostanie uwierzytelnione na podstawie biletu zapisanego w pliku cookie.Dobry artykuł na ten temat:
http://www.ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html(uszkodzony link)Edytować:
Ponieważ powyższy link jest zepsuty, poleciłbym rozwiązanie LukeP w jego odpowiedzi powyżej: https://stackoverflow.com/a/10524305 - Sugeruję również zmianę przyjętej odpowiedzi na tę.
Edycja 2: Alternatywa dla uszkodzonego linku: https://web.archive.org/web/20120422011422/http://ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html
źródło
Cache
jakoSession
zamiennika do przechowywania danych na serwerze. Czy ktoś może mi powiedzieć, czy jest to wadliwe podejście?Oto przykład wykonania pracy. bool isValid jest ustawiany przez przeglądanie jakiegoś magazynu danych (powiedzmy, że twoja baza danych użytkownika). UserID to tylko identyfikator, który utrzymuję. Możesz dodać dodatkowe dane, takie jak adres e-mail, do danych użytkownika.
w golbal asax dodaj następujący kod, aby odzyskać informacje
Aby później skorzystać z tych informacji, możesz uzyskać dostęp do niestandardowej nazwy użytkownika w następujący sposób.
pozwoli ci to uzyskać dostęp do niestandardowych informacji o użytkowniku.
źródło
MVC udostępnia metodę OnAuthorize, która zawiesza się z klas kontrolerów. Lub możesz użyć niestandardowego filtra akcji, aby wykonać autoryzację. MVC sprawia, że jest to dość łatwe. Zamieściłem tutaj post na blogu. http://www.bradygaster.com/post/custom-authentication-with-mvc-3.0
źródło
Oto rozwiązanie, jeśli musisz podłączyć pewne metody do @User do użycia w twoich widokach. Nie ma rozwiązania dla jakiejkolwiek poważnej personalizacji członkostwa, ale gdyby pierwotne pytanie było potrzebne tylko dla widoków, być może to wystarczyłoby. Poniższe informacje wykorzystano do sprawdzenia zmiennej zwróconej z filtru autoryzacji, służącej do sprawdzenia, czy niektóre łącza nie mają być prezentowane, czy też nie (nie w przypadku logiki autoryzacji lub przyznania dostępu).
Następnie po prostu dodaj odniesienie w obszarach web.config i nazwij je jak poniżej w widoku.
źródło
Na podstawie odpowiedzi LukeP i dodaj kilka metod konfiguracji
timeout
irequireSSL
współpracyWeb.config
.Odnośniki do linków
Zmodyfikowane kody LukeP
1, Ustaw
timeout
na podstawieWeb.Config
. FormsAuthentication.Timeout dostanie wartość limitu czasu, który jest zdefiniowany w pliku web.config. Zapakowałem następujące funkcje, które są funkcją zwrotnąticket
.2, Skonfiguruj plik cookie, aby był bezpieczny lub nie, w zależności od
RequireSSL
konfiguracji.źródło
W porządku, więc jestem poważnym kryptowalutą, przeciągając to bardzo stare pytanie, ale istnieje o wiele prostsze podejście do tego, o czym wspomniał @Baserz powyżej. I to jest użycie kombinacji metod rozszerzenia C # i buforowania (NIE używaj sesji).
W rzeczywistości Microsoft dostarczył już wiele takich rozszerzeń w
Microsoft.AspNet.Identity.IdentityExtensions
przestrzeni nazw. Na przykładGetUserId()
jest metodą rozszerzenia, która zwraca identyfikator użytkownika. Jest teżGetUserName()
iFindFirstValue()
, który zwraca roszczenia na podstawie IPrincipal.Musisz tylko podać przestrzeń nazw, a następnie zadzwonić
User.Identity.GetUserName()
aby uzyskać nazwę użytkownika skonfigurowaną przez ASP.NET Identity.Nie jestem pewien, czy jest to buforowane, ponieważ starsza tożsamość ASP.NET nie jest open source, i nie zadałem sobie trudu, aby ją odtworzyć. Jeśli jednak tak nie jest, możesz napisać własną metodę rozszerzenia, która będzie buforować ten wynik przez określony czas.
źródło
IsUserAdministrator
lubUserEmail
itp? MyśliszHttpRuntime.Cache
?Jako dodatek do kodu LukeP dla użytkowników formularzy internetowych (nie MVC), jeśli chcesz uprościć dostęp do kodu za twoimi stronami, po prostu dodaj poniższy kod do strony podstawowej i uzyskaj stronę podstawową na wszystkich swoich stronach:
Tak więc w swoim kodzie możesz po prostu uzyskać dostęp:
W scenariuszu z formularzem sieciowym brakuje mi tego, jak uzyskać takie samo zachowanie w kodzie niepowiązanym ze stroną, na przykład w httpmodules czy zawsze powinienem dodawać rzutowanie w każdej klasie, czy też jest lepszy sposób na uzyskanie tego?
Dzięki za odpowiedzi i dziękujemy LukeP ponieważ użyłem swoich przykłady jako baza dla mojego niestandardowego użytkownika (który ma teraz
User.Roles
,User.Tasks
,User.HasPath(int)
,User.Settings.Timeout
i wiele innych rzeczy ładne)źródło
Wypróbowałem rozwiązanie sugerowane przez LukeP i okazało się, że nie obsługuje ono atrybutu Autoryzuj. Więc trochę to zmodyfikowałem.
I wreszcie w Global.asax.cs
Teraz mogę uzyskać dostęp do danych w widokach i kontrolerach, po prostu dzwoniąc
Aby się wylogować, po prostu dzwonię
gdzie jest AuthManager
źródło