Autoryzacja Nancy.Authentication.Forms

Postaram się pokazać jak użyć Nancy.Authentication.Forms dla projektu, który jest migrowany z ASP.NET MVC do platform NancyFx + PetaPoco. Połączenie NancyFx i PetaPoco wydaje się bardzo lekkim rozwiązaniem, które jest w stanie przejąć na siebie zadania ociężałego tandemu MVC + EntityFramework.

Instalacja

Aby skorzystać z Nancy.Authentication.Forms należy najpierw zainstalować pakiet używając NuGet

Jeśli pakiet PetaPoco nie jest jeszcze zainstalowany to należy go dodać właśnie teraz.

Konieczny także będzie pakiet Microsoft.AspNet.WebPages, z uwagi na klasę System.Web.Helpers.Crypto pomocną przy operacjach na hasłach.

Zaczynamy programowanie

Spadek po ASP.NET Identity

Migrując istniejący projekt ASP.NET MVC zapewne mamy zestaw tabel w bazie, które zawierają informacje o użytkownikach. Szczęśliwie możemy posłużyć się istniejącą tabelą AspNetUsers, której pole Id zdefiniowane jako nvarchar(128) w rzeczywistości przechowuje GUIDy. Nie spotkałem się przynajmniej z inną sytuacją. Czemu Guid jest ważny? Okaże się za chwilę.

Zdefiniujmy klasy modelu z użyciem anotacji PetaPoco:

IUserIdentity

Następnie należy zaimplementować kilka interfejsów. Na początek IUserIdentity, który przechowuje podstawowe informacje o zalogowanym użytkowniku czyli jego nazwę i zestaw udzielonych mu praw.

IUserMapper

Z użyciem tej klasy zaimplementujemy interfejs Nancy.Authentication.Forms.IUserMapper. Zadaniem klasy implementującej ten interfejs jest dostarczenie informacji o użytkowniku (w postaci instancji IUserIdentity) na podstawie identyfikatora, którym jest Guid.

Podłączenie do NancyFx

Stworzone powyżej mechanizmy należy podłączyć do Nancy. Do tego celu posłużę się klasą Bootstrapera, który jest odpowiedzialny za wiele aspektów pracy frameworka.

IUserMapper

Jeśli w projekcie wcześniej nie został dodany Bootstraper to należy teraz dodać nową klasę dziedziczącą po DefaultNancyBootstrapper. Poniższy dodatek rejestruje klasę NancyUserMapper w kontenerze IoC. Dla mniej wtajemniczonych: oznacza to tyle, że kiedy gdzieś potrzebna będzie klasa implementująca interfejs IUserMapper to kontener IoC stworzy instancję stworzonej przez nas klasy NancyUserMapper.

Endy Tjahjono pisze, że jest to krok opcjonalny, po szczegóły odsyłam do jego artykułu – link na dole artykułu.

Aktywacja FormsAuthentication

Druga zmiana bootstrapera aktywuje mechanizm FormsAuthentication poprzez dołączenie go na początku kolejki przetwarzania żądania HTTP. Jednocześnie podana jest tam ścieżka ~/login, gdzie klient zostanie przekierowany w przypadku próby nieautoryzowanego dostępu do chronionego adresu url. Jak łatwo się domyślić pod adresem /login/ znajdzie się formularz logowania.

Formularz logowania

Obsługę formularza logowania zaimplementujemy w module LoginModule wspomaganym widokiem Login.cshtml. Jako model posłuży klasa LoginModel.

Model

Zacznijmy od modelu zawierające pola niezbędne do zalogowania.

Moduł

Moduł LoginModule będzie odpowiedzialny za obsługę żądań HTTP związanych z logowaniem.

Kilka słów komentarza do modułu:
Należy pamiętać o zaimportowaniu przestrzeni nazw Nancy.Authentication.Forms gdzie zaimplementowane są metody rozszerzające LoginAndRedirect i LogoutAndRedirect.

Przy wywołaniu tych metod należy pamiętać o podaniu ścieżki przekierowania po poprawnym zakończeniu akcji logowania lub wylogowania. Zwłaszcza w przypadku LoginAndRedirect jest tu pewien haczyk. Trzeci parametr posiada ustawioną wartość domyślną „/” co w wielu przypadkach powoduje, że aplikacja działa poprawnie. Zalecam jednak użycie ścieżki poprzedzonej tyldą np „~/” gdyż w przypadku instalacji aplikacji w wirtualnej ścieżce serwera HTTP przekierowanie bez tyldy nie będzie działać poprawnie.

Do sprawdzenia poprawności hasła użyłem metody VerifyHashedPassword zdefiniowanej w klasie System.Web.Helpers.Crypto. W przypadku powodzenia użytkownik jest przekierowywany powrotnie do strony, z której przybył do formularza logowania. W przypadku błędnego logowania wyświetlany jest ponownie formularz logowania opatrzony komunikatem przechowywanym z zmiennej ViewBag.ErrorMessage.

Widok

Do stworzenia widoku posłużyłem się razorem. Do projektu dodałem plik \Views\Login\Login.cshtml z kodem podanym poniżej. Poza zwykłym formularzem dodane jest tu odwołanie do szablonu Shared/_Layout.cshtml (pamiętamy o użyciu / zamiast \). Wskazałem też klasę bazową dla widoku Nancy.ViewEngines.Razor.NancyRazorViewBase, gdzie LoginModel jest klasą zdefiniowaną powyżej. Ponadto formularz jest wystylizowany pod Twitter Bootstrap.

Koniec wieńczy dzieło

W końcu można przetestować całość dodając żądane autoryzacji do modułu:

Należy pamiętać o dodaniu przestrzeni nazw Nancy.Security, gdyż tam znajduje się metoda rozszerzająca RequiresAuthentication.

Źródła