Próbuję utworzyć niestandardowy atrybut autoryzacji w programie ASP.NET Core. W poprzednich wersjach można było zastąpić bool AuthorizeCore(HttpContextBase httpContext)
. Ale to już nie istnieje AuthorizeAttribute
.
Jakie jest obecne podejście do tworzenia niestandardowego atrybutu autoryzacji?
Co próbuję osiągnąć: otrzymuję identyfikator sesji w Autoryzacji nagłówka. Z tego identyfikatora będę wiedział, czy dana akcja jest poprawna.
Odpowiedzi:
Podejście zalecane przez zespół ASP.Net Core polega na wykorzystaniu nowego projektu polityki, który jest tutaj w pełni udokumentowany . Podstawową ideą nowego podejścia jest użycie nowego atrybutu [Autoryzuj], aby wyznaczyć „zasadę” (np. Gdy
[Authorize( Policy = "YouNeedToBe18ToDoThis")]
zasada jest zarejestrowana w Startup.cs aplikacji w celu wykonania jakiegoś bloku kodu (tj. Zapewnienia, że użytkownik ma roszczenie wiekowe w wieku 18 lat lub starszych).Projekt polityki jest doskonałym dodatkiem do frameworka, a zespół ASP.Net Security Core powinien być pochwalony za jego wprowadzenie. To powiedziawszy, nie jest odpowiednie dla wszystkich przypadków. Wadą tego podejścia jest to, że nie zapewnia ono wygodnego rozwiązania najczęstszej potrzeby zwykłego stwierdzenia, że dany kontroler lub działanie wymaga określonego typu roszczenia. W przypadku, gdy aplikacja może mieć setki dyskretnych uprawnień rządzących operacjami CRUD na poszczególnych zasobach REST („CanCreateOrder”, „CanReadOrder”, „CanUpdateOrder”, „CanDeleteOrder” itp.), Nowe podejście wymaga powtarzalnych czynności jeden do jednego jedno odwzorowanie między nazwą polisy a nazwą roszczenia (np
options.AddPolicy("CanUpdateOrder", policy => policy.RequireClaim(MyClaimTypes.Permission, "CanUpdateOrder));
) lub napisanie kodu w celu wykonania tych rejestracji w czasie wykonywania (np. odczytanie wszystkich typów oświadczeń z bazy danych i wykonanie wyżej wspomnianego wywołania w pętli). Problem z tym podejściem w większości przypadków polega na tym, że jest to niepotrzebny narzut.Chociaż zespół ASP.Net Core Security zaleca, aby nigdy nie tworzyć własnego rozwiązania, w niektórych przypadkach może to być najbardziej rozważna opcja, od której można zacząć.
Poniżej przedstawiono implementację, która wykorzystuje IAuthorizationFilter w celu zapewnienia prostego sposobu wyrażenia wymogu dotyczącego roszczenia dla danego kontrolera lub działania:
źródło
new ForbidResult()
nie działa (powoduje wyjątek / 500), ponieważ nie ma powiązanego schematu autoryzacji. Z czego skorzystałbym w tej sprawie?Jestem osobą zabezpieczającą asp.net.
Po pierwsze, przepraszam, że nic z tego nie jest jeszcze udokumentowane poza próbkami lub testami jednostkowymi w sklepie muzycznym, a wszystko to jest wciąż udoskonalane pod względem odsłoniętych interfejsów API.Szczegółowa dokumentacja jest tutaj .Nie chcemy, abyś pisał niestandardowe atrybuty autoryzacji. Jeśli musisz to zrobić, zrobiliśmy coś złego. Zamiast tego powinieneś pisać wymagania dotyczące autoryzacji .
Autoryzacja działa na Tożsamości. Tożsamości są tworzone przez uwierzytelnianie.
W komentarzach mówisz, że chcesz sprawdzić identyfikator sesji w nagłówku. Twój identyfikator sesji będzie podstawą tożsamości. Jeśli chcesz użyć
Authorize
atrybutu, napiszesz oprogramowanie pośredniczące do uwierzytelniania, aby pobrać ten nagłówek i przekształcić go w uwierzytelnionyClaimsPrincipal
. Następnie sprawdziłbyś to w ramach wymogu autoryzacji. Wymagania dotyczące autoryzacji mogą być tak skomplikowane, jak chcesz, na przykład tutaj, która przyjmuje datę urodzenia na podstawie bieżącej tożsamości i autoryzuje, jeśli użytkownik ma ukończone 18 lat;Następnie w swojej
ConfigureServices()
funkcji załączyłbyś goNa koniec zastosuj go do kontrolera lub metody akcji za pomocą
źródło
ManageStore
wymagana jest próbka z Music Store. Ponieważ jest to w próbce, istnieje tylko „albo zezwól na wszystko albo nic”. Czy musimy stworzyć nową politykę dla każdej możliwej permutacji? tzn. „Użytkownicy / Odczytaj”, „Użytkownicy / Utwórz”, „Użytkownicy / AssignRole”, „Użytkownicy / Usuń”, jeśli chcemy uzyskać szczegółowe wnioski? Wygląda na to, że praca nad konfiguracją jest wystarczająca, a obfitość zasad tylko po to, by zarządzać roszczeniami, a nie[ClaimsAutzorization("User", "Read", "Create", "Delete", "Assign")]
atrybutem?[CustomAuthorize(Operator.And, Permission.GetUser, Permission.ModifyUser)]
. Mógłbym użyć jednego niestandardowego atrybutu na nieskończoną liczbę sposobów, po prostu modyfikując parametry konstruktora.IAuthorizeData.Policy
) i niestandardowych dostawców polityk, aby przezwyciężyć ten rażący nadzór, zamiast zajmować się nim w ramach. Myślałem, że nie powinniśmy tworzyć własnych wdrożeń? Kilku z nas nie pozostawiło innego wyboru, jak tylko ponownie wdrożyć autoryzację od zera (tym razem), tym razem bez korzyści ze staregoAuthorize
atrybutu interfejsu API sieci Web . Teraz musimy to zrobić na poziomie filtra akcji lub oprogramowania pośredniego.Wydaje się, że dzięki ASP.NET Core 2 możesz ponownie odziedziczyć
AuthorizeAttribute
, wystarczy zaimplementowaćIAuthorizationFilter
(lubIAsyncAuthorizationFilter
):źródło
OnAuthorization
implementacja musi poczekać na metodę asynchroniczną, powinieneś zaimplementowaćIAsyncAuthorizationFilter
zamiast tegoIAuthorizationFilter
filtr wykona się synchronicznie, a akcja kontrolera zostanie wykonana niezależnie od wyniku filtru.Na podstawie Dereka Greera WIELKIEGO , zrobiłem to z wyliczeniami.
Oto przykład mojego kodu:
źródło
Możesz utworzyć własny obiekt AuthorizationHandler, który znajdzie niestandardowe atrybuty na kontrolerach i akcjach oraz przekaże je do metody HandleRequirementAsync.
Następnie możesz użyć go do dowolnych niestandardowych atrybutów na kontrolerach lub działaniach. Na przykład, aby dodać wymagania dotyczące uprawnień. Wystarczy utworzyć niestandardowy atrybut.
Następnie utwórz Wymaganie, aby dodać do swojej Polityki
Następnie utwórz obiekt AuthorizationHandler dla niestandardowego atrybutu, dziedzicząc obiekt AttributeAuthorizationHandler, który utworzyliśmy wcześniej. Zostanie przekazany IEnumerable dla wszystkich niestandardowych atrybutów w metodzie HandleRequirementsAsync, zebranych z kontrolera i działania.
Na koniec w metodzie Startup.cs ConfigureServices dodaj niestandardowy moduł obsługi autoryzacji do usług i dodaj swoją politykę.
Teraz możesz po prostu ozdobić swoje kontrolery i akcje niestandardowym atrybutem.
źródło
Łatwe: nie twórz własnych
AuthorizeAttribute
.W przypadku scenariuszy obejmujących wyłącznie autoryzację (takich jak ograniczenie dostępu tylko do określonych użytkowników) zalecanym podejściem jest użycie nowego bloku autoryzacji: https://github.com/aspnet/MusicStore/blob/1c0aeb08bb1ebd846726232226279bbe001782e1/samples/MusicStore/Startup.cs#L84 -L92
W przypadku uwierzytelniania najlepiej postępować na poziomie oprogramowania pośredniego.
Co dokładnie próbujesz osiągnąć?
źródło
Jeśli ktoś chce tylko zweryfikować token nośnika w fazie autoryzacji, korzystając z bieżących praktyk bezpieczeństwa, możesz:
dodaj to do Startup / ConfigureServices
i to w twojej bazie kodów,
Jeśli kod nie osiągnie
context.Succeed(...)
, i tak się nie powiedzie (401).A potem możesz użyć kontrolerów
źródło
Współczesny sposób to AuthenticationHandlers
w startup.cs dodaj
IUserService to usługa, którą wykonujesz, gdzie masz nazwę użytkownika i hasło. w zasadzie zwraca klasę użytkownika, której używasz do mapowania swoich roszczeń.
Następnie możesz zapytać o te roszczenia, a ona dowolne dane, które zmapowałeś, jest ich sporo, spójrz na klasę ClaimTypes
możesz użyć tego w metodzie rozszerzenia i uzyskać dowolne mapowanie
Myślę, że ten nowy sposób jest lepszy niż
źródło
W tym piśmie uważam, że można to osiągnąć za pomocą interfejsu IClaimsTransformation w wersji asp.net core 2 i nowszych. Właśnie wdrożyłem dowód koncepcji, który można udostępnić tutaj.
Aby użyć tego w swoim kontrolerze, po prostu dodaj odpowiedni
[Authorize(Roles="whatever")]
do swoich metod.W naszym przypadku każde żądanie zawiera nagłówek autoryzacji, który jest JWT. To jest prototyp i wierzę, że zrobimy coś bardzo zbliżonego do tego w naszym systemie produkcyjnym w przyszłym tygodniu.
Przyszli wyborcy, weź pod uwagę datę pisania podczas głosowania. Na dzień dzisiejszy to
works on my machine.
™ Prawdopodobnie będziesz potrzebować więcej obsługi błędów i logowania do swojej implementacji.źródło
Do autoryzacji w naszej aplikacji. Musieliśmy zadzwonić do usługi na podstawie parametrów przekazanych w atrybucie autoryzacji.
Na przykład, jeśli chcemy sprawdzić, czy zalogowany lekarz może przeglądać wizyty pacjentów, przekazujemy „View_Appointment”, aby niestandardowy atrybut autoryzacji i sprawdzić to bezpośrednio w usłudze DB i na podstawie wyników autoryzujemy. Oto kod tego scenariusza:
A przy akcji API używamy go w następujący sposób:
źródło
Przyjęta odpowiedź ( https://stackoverflow.com/a/41348219/4974715 ) nie jest realistycznie możliwa do utrzymania ani odpowiednia, ponieważ „CanReadResource” jest używany jako roszczenie (ale zasadniczo powinien być polityką w rzeczywistości, IMO). Podejście do odpowiedzi nie jest OK w sposobie, w jaki zostało użyte, ponieważ jeśli metoda działania wymaga wielu różnych konfiguracji oświadczeń, wówczas przy tej odpowiedzi musiałbyś wielokrotnie pisać coś takiego ...
Wyobraź sobie, ile to zajmie kodowanie. Idealnie, „CanReadResource” ma być polityką, która korzysta z wielu oświadczeń w celu ustalenia, czy użytkownik może odczytać zasób.
To, co robię, to tworzę swoje zasady jako wyliczenie, a następnie przeglądam i konfiguruję wymagania w ten sposób ...
Klasa DefaultAuthorizationRequirement wygląda jak ...
Pamiętaj, że powyższy kod może również umożliwić wstępne mapowanie użytkownika na zasady w magazynie danych. Tak więc, podczas tworzenia oświadczeń dla użytkownika, zasadniczo pobierasz zasady, które zostały wcześniej zmapowane bezpośrednio do użytkownika bezpośrednio lub pośrednio (np. Ponieważ użytkownik ma określoną wartość oświadczenia i ta wartość oświadczenia została zidentyfikowana i odwzorowana na polisę, taką jak że zapewnia automatyczne mapowanie dla użytkowników, którzy również mają tę wartość oświadczenia), i zapisuje zasady jako oświadczenia, tak że w module obsługi autoryzacji możesz po prostu sprawdzić, czy oświadczenia użytkownika zawierają wymóg. Polityka jako wartość elementu oświadczenia w ich roszczenia. Dotyczy to statycznego sposobu spełnienia wymogu polityki, np. Wymóg „Imię” ma charakter dość statyczny. Więc,
Wymaganie dynamiczne może dotyczyć sprawdzania przedziału wiekowego itp., A zasad korzystających z takich wymagań nie można wstępnie mapować na użytkowników.
Przykład dynamicznego sprawdzania roszczeń dotyczących zasad (np. W celu sprawdzenia, czy użytkownik ma więcej niż 18 lat) znajduje się już w odpowiedzi udzielonej przez @blowdart ( https://stackoverflow.com/a/31465227/4974715 ).
PS: Napisałem to na telefonie. Ułaskaw wszelkie literówki i brak formatowania.
źródło