SignalR w ASP.NET Core i Angular – przykładowa implementacja

Niedawno opublikowałem wpis na temat instalacji biblioteki SignalR w projekcie ASP.NET Core z wykorzystaniem Angulara. Dzisiaj chciałem kontynuować ten temat na przykładzie z mojego projektu. Zademonstruję działającą implementację po stronie serwera.

Link do poprzedniego wpisu: SignalR w ASP.NET Core – instalacja i uruchomienie

Konfiguracji ciąg dalszy

Chociaż konfiguracja jaką podałem w ostatnim wpisie wystarczała do działania, w moim rozwiązaniu musiałem dodać jeszcze kilka ustawień. Na pierwszy ogień poszedł CamelCasePropertyNamesContractResolver, dobrze znany wszystkim, którzy tworzyli kiedyś API w Asp.Net. Dzięki niemu, obiekty zwracane są z API w notacji CamelCase. Jest to domyślne ustawienie w .NET Core, ale jako że my mamy podpiętą bibliotekę ze starszej wersji frameworka, musimy ustawić to ręcznie. Przykładowa implementacja poniżej.

Następnie rejestrujemy nasz serializator w pliku Startup.cs.

Rozsyłanie eventów z poziomu backendu aplikacji

Wysłanie zdarzenia z serwera może odbyć w dwóch przypadkach:

  • Bezpośrednio z naszej klasy, dziedziczącej po Hub, w momencie gdy klient wywołuje zdalną metodę na serwerze
  • Po wywołaniu zwykłej metody HTTP w API, pośrednio poprzez Hub

O ile w pierwszym przypadku jest to bardzo proste, to ten drugi wymaga dodatkowego nakładu pracy. Załóżmy że nasz Hub ma tylko jedną metodę.

Klient, w momencie gdy wywoła metodę Subscribe, zapisze się do grupy odpowiadającej identyfikatorowi gry. Zwrócone mu zostanie id jego połączenia. Wewnątrz klasy Broadcaster możemy wysłać zdarzenie o nowej subskrypcji do wszystkich klientów. Taki przykład podałem w poprzednim poście, dlatego tutaj to pomijam (nie jest to potrzebne w moim przypadku). Efekt który chcemy tutaj osiągnąć to wysłanie do każdego klienta informacje o tym, że gracz wykonał ruch. Jako przykład posłuży tutaj zakończenie tury przez gracza.

Podczas wywołania tej akcji kontrolera, wywołujemy metodę SkipRound. Wewnątrz niej, po tym jak nastąpi zmiana kolejki, chcielibyśmy poinformować wszystkich graczy o tym fakcie. Nasz Hub to nie jest zwykła klasa, którą można po prostu wstrzyknąć do naszych obiektów. W tym celu musimy odwołać się do klasy ConnectionManager dostarczonej przez SignalR.

Dodałem klasę EventBroadcaster, która będzie odpowiedzialna za przekazywanie informacji do klientów bezpośrednio z serwera. Posiada ona obiekt HubContext, który umożliwia takie działania. Dostępny jest po wywołaniu metody GlobalHost.ConnectionManager.GetHubContext. Ponieważ jej wywołanie jest dosyć czasochłonne, klasę EventBroadcaster rejestrujemy w systemie jako singleton.

Dzięki temu, w dowolne miejsce aplikacji możemy dodać obiekt implementujący IEventBroadcaster i wysyłać do klientów interesujące nas zdarzenia. Przykład poniżej.

Podsumowanie

Dzisiaj zademonstrowałem przykładową implementację rozsyłania zdarzeń w aplikacji po stronie serwera aplikacji. W kolejnym wpisie zajmiemy się implementacją po stronie klienta w Angularze. Dzięki za uwagę i zapraszam ponownie!

Co nowego w projekcie – aktualizacja

Od ostatniej aktualizacji minęły prawie dwa tygodnie, więc pora na krótkie podsumowanie tego, co udało mi się zrobić przez ten czas. Niestety dla projektu, przez dwa ostatnie weekendy byłem poza domem, więc nie wszystko co sobie zaplanowałem zostało zrealizowane. Jakieś postępy jednak są, dlatego zapraszam do lektury!

post-background

Exception handling w WebAPI

Przechwytywanie błędów to było coś, co mi się nie podobało w moim rozwiązaniu. Wiadomo, na początku nie było to istotne, ale w miarę jak ilość elementów aplikacji rosła, trzeba było pomyśleć nad czymś sensownym. Domyślnie, gdy w aplikacji pojawiał się błąd, wyświetlana była strona z jego treścią, standardowe zachowanie. Jako, że w API nie jest to pożądane, dodałem do aplikacji middleware który przechwytuje wszystkie wyjątki. W ten sposób nie trzeba się bawić w przekazywanie statusów z metod domeny do kontrolera – gdy trzeba rzucamy wyjątek odpowiedniego typu, a resztą zajmie się właśnie ten fragment kodu.

Teraz tylko dodajemy tą klasę do pipeline w ASP poprzez metodę UseMiddleware<ExceptionHandlingMiddleware>() i gotowe. Wszystkie wyjątki zostaną przechwycone i zwrócone do klienta. W zależności od rodzaju wyjątku, zwrócony zostanie inny status błędu.

Obsługa SignalR

Mój poprzedni post jest w całości poświęcony tej tematyce, a w szczególności wspominam tam o wszystkich problemach jakie mnie spotkały podczas dodawania tej biblioteki. Warto jednak o tym tutaj wspomnieć. Dzięki temu moja aplikacja będzie mogła działać w czasie rzeczywistym, rozsyłając komunikaty pomiędzy wszystkich klientów. O tym, jak dokładnie zostało to zaimplementowane po stronie klienta i serwera opowiem w kolejnych postach.

Praca nad widokiem aplikacji

W miarę jak dodaje kolejne elementy, powoli buduje interfejs użytkownika. Na razie ten element wyraźnie kuleje, ale nie jest to najistotniejsze w tym momencie. Wygląd na tą chwilę nie jest istotny, ważne żeby dokładać kolejne elementy funkcjonalne. Obecnie pracuje nad planszą do gry. Jest to dosyć problematyczne zadanie, ponieważ staram się żeby była możliwość gry na tabletach i smartfonach. Ciężko pomieścić tak wiele pól na małych ekranach tak, żeby były one czytelne. Do tego CSSy to nie jest moja mocna strona… Na razie poprawki tego fragmentu zostawiam na później. Nie będę się także chwalił obecnym wyglądem aplikacji, myślę że w przyszłym tygodniu coś już pokażę.

Dalsza praca z Dapperem

Tej technologii też poświęciłem już cały wpis, ale chciałem pokazać kolejną metodę którą udostępnia. Jest to QueryMultipleAsync. Tak bardzo mi się to spodobało, że postanowiłem o tym tutaj wspomnieć. Po wejściu na planszę klient chce pobrać informacje o obecnej grze: pola, status, drużyny etc. W tym celu odpytuje API. Zamiast wielu zapytań do bazy danych, całą tą operację da się zrobić w jednym zapytaniu. Można by to wydzielić na wiele mniejszych zapytań, ale stwierdziłem że to dobry moment na wykorzystanie tej metody. Poniżej implementacja.

AccessQueries w powyższym przykładzie to po prostu treści zapytań SQL. Z wielu małych zapytań generowane jest jedno wielkie. Wyniki są mapowane do poszczególnych elementów obiektu Game. W SQL Server Profilerze wyraźnie widać, wszystko wykonane w jednej operacji, bardzo miła sprawa.

Sql Server Profiler - wynik zapytania QueryMultipleAsync

Zrzut ekranu z SQL Server Profiler

Podsumowanie

Podkręciłem ostatnio tempo pracy nad projektem, dodatkowo zapowiada mi się pierwszy wolny weekend w tym miesiącu, dlatego mam spore oczekiwania względem tego, co uda mi się zrobić w najbliższych dniach! Stay tuned!

SignalR w ASP.NET Core – instalacja i uruchomienie

Dzisiaj chciałem podzielić się moimi doświadczeniami z użyciem biblioteki SignalR w projekcie .NET Core. Co prawda, nie mam jeszcze za dużo przykładów użycia w projekcie, ponieważ dopiero udało mi się zmusić ją do działania. Wydaje mi się jednak, że to co tutaj opiszę przyda się komuś, jeżeli napotka na podobne problemy co ja.

signalr sign and pretty tree

Co to jest SignalR?

SignalR to biblioteka pozwalająca na tworzenie aplikacji aktualizujących dane w czasie rzeczywistym. Co to znaczy? W standardowym scenariuszu, po uruchomieniu strony czy aplikacji pobierane są dane. Jeżeli chcemy je odświeżyć, musimy przeładować stronę lub wywołać jakąś akcję która odświeży dane (np. ponowne przefiltrowanie listy). W taki czy inny sposób wysyłamy żądanie na serwer i otrzymujemy od niego odpowiedź. Tutaj mamy do czynienia z czymś innym. To serwer informuje klienta o tym, że dane zostały zmienione. Dzięki temu natychmiast możemy mieć dostęp do interesujących nas informacji. W tym celu stosowane jest na przykład API WebSockets, czyli komunikacja dwukierunkowa klient-serwer. Do naszej dyspozycji jest także HTML5 Server-Sent Events. Tutaj komunikacja jest tylko jednokierunkowa, z serwera do klienta. Bywa jednak, że przeglądarki nie wspierają obu tych rozwiązań. Wtedy z pomocą przychodzi SignalR. Korzystając z niego nie interesuje nas w jaki sposób przebiegać będzie komunikacja, framework zajmie się tym za nas. Jeżeli tak jak wspomniałem przed chwilą, przeglądarka nie dostarcza nam tych rozwiązań, wykonane zostaną po prostu zwykłe zapytania. Ale to już jest dla programisty mało ważne, stanie się to automatycznie. To tyle w skrócie, nie są to technologie nowe, dlatego po więcej szczegółów zachęcam do dalszej lektury we własnym zakresie.

SignalR w .NET Core

Na początek pokaże, co zrobić żeby wszystko ładnie działało po stronie API naszej aplikacji. Największym problemem na jaki napotkałem był brak implementacji biblioteki pod .NET Core. Jest ona jeszcze w przygotowaniu, i żeby mieć tą wersję, trzeba ją pobrać ze specjalnego źródła, gdzie wrzucane są wersje dopiero rozwijane. Stwierdziłem, że nie będę się katował wersjami testowymi tej technologi. Sami autorzy tego nie zalecają. Do tego musiałbym podnieść wersję samego .NET Core, a tego nie chciałem robić. Wystarczą mi problemy, które mam z wersją stabilną… Jako, że byłem zmotywowany do użycia tej technologi i nie chciałem po prostu odpytywać serwera co chwilę o to, czy pozostali gracze nie wykonali ruchu, znalazłem inne rozwiązanie. Postanowiłem, że użyję frameworka .NET w wersji 4.6.2. Nie wiązało się to z przepisywaniem aplikacji od nowa. Moja aplikacja dalej pisana jest w .NET Core, ale mam możliwość korzystania ze sprawdzonych bibliotek poprzedniej wersji .NET. Wystarczy zmienić trochę plik .csproj naszej aplikacji.

Zamiast netcoreapp1.1, jako TargetFramework podajemy net462. Reszta aplikacji pozostaje w zasadzie bez zmian. Dzięki temu, dalej korzystamy z nowego .NET Core, ale możemy dodać zależności do sprawdzonego Microsoft.AspNet.SignalR.Core. W ten sposób omijamy pierwszą przeszkodę, czyli wersję biblioteki. To jednak nie wszystko.
Żeby móc podpiąć SignalR do pipeline’u naszej aplikacji, musimy dodać następujące extension methods.

Kluczowe tutaj było dodanie do pipeline UseAesDataProtectorProvider. Bez tego, SignalR działał lokalnie, ale już w środowisku produkcyjnym nie chciał nawiązać połączenia. Objawiało się to błędem Error during negotiation request.... Po wykonaniu tych czynności możemy dodać SignalR do naszej aplikacji!

A poniżej pierwszy Hub, którym testowałem, czy komunikacja działa. Nie robi nic innego, niż tylko przekazanie wszystkim połączonym klientom otrzymanej wiadomości.

SignalR w Angular

Kolejne problemy, na szczęście mniejsze, pojawiły się po stronie frontendu aplikacji. Jak zwykle jakąś rolę odegrał tutaj Webpack, ale do tego już się przyzwyczaiłem. Do komunikacji z serwerem użyłem biblioteki ng2-signalr, która dostarcza implementacje pod Angulara. Problem polegał na tym, że nie widziała ona dodanych do projektu bibliotek jQuery oraz signalr, które są konieczne do jej działania. Do obejścia tego problemu w pliku webpack.config.js należało dodać nowy plugin, który automatycznie ładuje moduły do wybranego identyfikatora. Dodatkowo w app.module.ts należało dodać importy tych bibliotek. Dzięki temu problem zniknął.

Teraz można przejść do właściwej implementacji naszego rozwiązania. Dodajemy resolver połączenia do SignalR, który już na starcie komponentu zwraca nam obiekt połączenia. W obecnej implementacji, zawsze łączy się do tego samego Huba.

Połączenie tworzone jest na podstawie domyślnej konfiguracji, która jest podawana podczas deklaracji modułu SingalR. Oto implementacja funkcji, podającej domyślną konfigurację.

Korzystam z tego samego mechanizmu, który wykorzystałem do konfiguracji całej aplikacji. Inne połączenie stosowane jest lokalnie, a inne na serwerze. Taką domyślną konfigurację przekazujemy w pliku app.module.ts.

Do funkcji connect obiektu SingalR w naszym resolverze możemy przekazać dodatkowe opcje, które nadpiszą te domyślne. W ten sposób możemy przekazać na przykład tylko nazwę Huba, do którego chcemy się połączyć. Serwer pobrany zostanie wtedy z domyślnej konfiguracji, jest to bardzo wygodne. W samym komponencie możemy teraz dostać obiekt połączenia do serwera w funkcji ngOnInit, o ile w deklaracji routingu dodaliśmy resolve przy pomocy wcześniej zaimplementowanego resolvera.

Podsumowanie

Na tą chwilę w aplikacji udało mi się zrobić tylko tyle w kwestii SignalR’a. Teraz mogę przejść do konkretnej implementacji mojego rozwiązania. Na pewno w kolejnych postach podzielę się jak ona wygląda.

Pierwsze kroki z Dapper’em oraz moje doświadczenia z ORM

Dzisiaj chciałem w skrócie opowiedzieć o tym, jak wprowadziłem do projektu nową bibliotekę. Słyszałem o niej już od jakiegoś czasu, ale nie miałem okazji z niej skorzystać. Kiedy lepiej niż teraz?! Tak więc zapraszam do krótkiego wpisu dotyczącego biblioteki Dapper.

Moja historia z ORM i nie tylko

W projektach .NETowych wykorzystywałem kilka sposobów dostępu do bazy danych. Na początku były to DataSety. Do dziś pamiętam ten dramat gdy trzeba było coś zmieniać w zapytaniach, lub wszystkie razy kiedy kod designera się wykrzaczył i trzeba było kombinować dlaczego.

Później przyszła pora na SqlCommand z ADO.NET. Ręczne mapowanie rezultatów zapytań, kolejny raz poprawianie kodu w wielu miejscach przy zmianach. Też nie było kolorowo, ale jednak nie trzeba było utrzymywać DataSetów. No i wydajność była wyśmienita. To już coś.

Następnie pojawił się EntityFramework w podejściu DatabaseFirst. Kolejny raz pojawił się designer, dodawanie tabelek, ale tutaj już nie trzeba było pisać żadnych procedur składowanych w SQL. Szybkie Linq i gotowe. Coś pięknego. Czar prysł dosyć szybko z kilku powodów. Pierwszy z nich to taki, że nie potrafiliśmy z niego dobrze korzystać. Globalny context na cały projekt? Dlaczego nie! Ogromne zapytania w Linq, które pięknie działają lokalnie, ale na produkcji już nie koniecznie. Oj tak! To było tylko kilka grzechów głównych, które popełniliśmy na początku. Kwestie wydajności można było zastąpić procedurami, ale przy takim podejściu w sumie ta praca wygląda jak ta z DataSetami, bleee. Tutaj pojawia się kolejny problem, czyli designer. Jak już wspomniałem, DataSety przebrane w kostium EF, a do tego z gorszą wydajnością. Nie będę tutaj dalej ciągnął tego wątku, bo to worek bez dna.

Następnie pojawił się EntityFramework, ale już taki „prawdziwy” przy podejściu CodeFirst. Kwestie problemów z wydajnością zapytań pozostają, ale nie mamy już tego przeklętego designera. Chociaż tyle. W tym momencie miałem już dużo większe doświadczenie i wiedziałem, że nie wszystko złoto co się świeci. Do prostych zapytań, jak najbardziej! Praca jest wtedy szybka, nie przejmujemy się za bardzo warstwą bazy danych. Sprawdzamy jedynie, czy EF nie wypluwa jakiegoś kosmicznego zapytania do BD (zawsze jest ono kosmiczne, ale chodzi o to, żeby dobrze działało) i voilà. Jest pięknie. Gdy mamy jakieś skomplikowane zapytanie, nie bójmy się napisać procedury, to nie jest takie złe jeżeli nie musimy tego robić za każdym razem. Na temat EF jest wiele artykułów, wiele z nich twierdzi wręcz, że ta technologia nie nadaje się do niczego. Moim zdaniem w większości przypadków takie podejście może być wystarczające (tak jak w przypadku mojego projektu), ale nie zawsze. Można sprawić, że takie rozwiązanie będzie działało bardzo szybko, ale stracimy wtedy ostatnie zalety, jakie daje EF, np. automatyczne sprawdzanie zmian. Jeżeli zależy nam na wydajności bez kompromisów, trzeba sięgnąć po coś innego.

Dapper

No i tak oto przechodzimy do Dappera. Jak można przeczytać na jego stronie, Dapper to prosty mapper obiektów dla .NET, który rozszerza interfejs IDbConnection. Jako jego główne zalety wymienić można wydajność oraz to, że nie jest ograniczany w żaden sposób przez typ bazy danych z jakiego korzystamy. Wszystkie typy, obsługiwane w .NET ADO np. SqlLite, Firebird, Oracle, MySQL, PosgreSQL czy SQL Server.

Po dwóch dniach odkąd zacząłem z nim pracować, muszę przyznać, że jestem mile zaskoczony. Prawda, trzeba pisać kod SQL, ale samo użycie biblioteki jest bajecznie proste, co zaraz zademonstruje na przykładach. Mamy tutaj zalety EF, gdzie nie trzeba mapować obiektów ręcznie, oraz czystego ADO.NET, gdzie nie trzeba utrzymywać żadnych designerów czy wielkich klas DbContextu. W moim przypadku nie jest to do końca prawda, bo EF służy mi do zarządzania użytkownikami w ASP.NET Identity oraz do wykonywania migracji. Tak więc nie pozbędę się EF z projektu. Prawda jest taka, że na moje potrzeby wystarcza on całkowicie, chodzi tutaj bardziej o naukę.

Ten prosty kawałek dodaje nowy wiersz i jednocześnie wyciąga dane z bazy danych. Najpierw mapujemy model z danymi gry na encje, dodajemy datę zapisu (moglibyśmy to zrobić na poziomie zapytania, ale wolę takiej logiki nie wydzielać z systemu). Później otwieramy połączenie. Tutaj wykorzystuję fabrykę, która pobiera z konfiguracji connection string do bazy. Na interfejsie IDbConnection wykonujemy metodę QueryFirstAsync, która pobiera i mapuje pierwszy wynik zapytania na wskazany typ obiektu i go zwraca. Nie ma tutaj niczego skomplikowanego.

Powyżej jeszcze zapytanie które jest wykonywane. Od razu pobierane są dane, które chce zwrócić na początek. Wszystko wykonane w jednym odwołaniu do bazy danych. Bardzo miło.

Do dyspozycji mamy jeszcze inne metody, które działają bardzo podobnie, np. Execute, która nie zwraca danych z bazy. Możemy przekazać obiekt transakcji, dzięki czemu możemy wykonać rollback zapytań w razie potrzeby. Taka dygresja, tutaj przekonałem się o tym, że .NET Core jeszcze raczkuje, ponieważ nie posiada w obecnej wersji TransactionScope, znanego z poprzednich wersji frameworka. Kolejna ciekawa opcja to możliwość wykonywania wielu zapytań w jednym odwołaniu do bazy poprzez QueryMultiple. Nie będę rozpisywał się za dużo o przykładach, ponieważ pełno ich w sieci, między innymi nas tronie którą podałem na początku tego posta.

Podsumowanie

Moje doświadczenia z Dapperem są na razie bardzo pozytywne. Nie wiem, czy będę do wykorzystywał do wszystkich zapytań w moim projekcie, ale na pewno do tych bardziej skomplikowanych sięgnę właśnie po niego. Zachęcam Was do zapoznania się z tą biblioteką.

Zabezpieczenie WebAPI w ASP.NET Core – Wprowadzenie

Dzisiaj chciałbym w skrócie omówić jak zabezpieczyć nasze API, które napisane jest w .NET Core. Jeżeli chcemy mówić o bezpieczeństwie aplikacji, musimy poznać i zrozumieć dwa bardzo ważne pojęcia, które często są ze sobą mylone:

  • Authentication, czyli uwierzytelnianie, to proces podczas którego sprawdzamy, czy dana osoba jest rzeczywiście tym za kogo się podaje.
  • Authorization, czyli autoryzacja, polega na ustaleniu, czy podmiot ma dostęp do zasobu po który wysłał żądanie.

Bardziej na ten temat nie będę się rozpisywał, zachęcam do bardziej dogłębnej lektury, po przeczytaniu mojego wpisu oczywiście.

Zło konieczne

W wielkich systemach zabezpieczenia to sprawa oczywista: finanse, adresy etc. Nikomu nie trzeba tłumaczyć, że te dane pod żadnym pozorem nie mogą wpaść w niepowołane ręce. Jednak rozwijając małą aplikację można sobie pomyśleć: „Po co mi zabezpieczenia, to tylko mały projekt po godzinach, kto chciałby mi się tutaj włamywać?”. Takie myślenie może być zgubne. W sieci grasuje wiele niebezpieczeństw i nawet, jeżeli nie mamy żadnych danych poufnych, to po prostu możemy paść ofiarą zwykłej złośliwości i utracić cenne dla nas dane. Tak mi się skojarzyło z obrazkiem poniżej, za każdym razem jak będziesz odczuwał pokusę udostępniania API bez zabezpieczeń, przypomnij sobie słowa Melisandre.

Satyryczny obrazek postaci z serialu Gra o Tron, ostrzegający o tym że "Internet jest ciemny i pełny strachu"

„Internet jest ciemny i pełny strachu”

Zdając sobie sprawę z zagrożeń o których wspomniałem, przystąpiłem do implementacji mojego API. Osobiście uważam, że jest to bardzo nudna część projektu, zło konieczne z którym trzeba się pogodzić. Cytując słowa Scotta Hanselmana: Shave the Yak, co oznacza mniej więcej tyle, że musimy się uporać z mniejszym problem, żebyśmy mogli przejść do konkretów.

Implementacja JWT Tokens

Na szczęście, do dyspozycji mamy wiele narzędzi które ułatwiają nam życie. Ja moje API zabezpieczam przy użyciu Tokenów JWT. Na razie przedstawię podejście minimalistyczne, w którym będziemy korzystali z indywidualnych kont użytkowników. W przyszłości chcę wykorzystać Social Login, czyli po prostu stare dobre Zaloguj się poprzez fejsbuka, gdzie oczywiście zamiast tego można wykorzystywać także Google, Twittera czy innego GitHub’a. No ale przejdźmy już do konkretów.

Na wstępie musimy dodać bazę danych, gdzie przechowywać będziemy użytkowników. Ja wykorzystam do tego Entity Framework. Dane konfiguracyjne przechowuje w plikach, które nie są wrzucone do repozytorium na GitHubie, a do ich odczytu dodałem własną klasę.

Teraz definiujemy z jakich narzędzi będziemy korzystać. Dzieje się to w pliku Startup.cs, w metodzie ConfigureServices. Najpierw konfigurujemy wykorzystanie systemu identyfikacji Identity dostępnego w paczce Microsoft.AspNetCore.Identity. W tym samym miejscu definiujemy, że do tego cely wykorzystamy właśnie Entity Framework.

Następnie konfigurujemy to, w jaki sposób aplikacja będzie uwierzytelniała użytkowników. Oto fragment tej metody:

UseJwtBearerTokenAuthentication to extension method, który dodałem w celu odchudzenia pliku Startup.cs. To dopiero początek pracy nad projektem, a ten już rośnie w niebezpiecznym tempie. Dlatego staram się wydzielać część konfiguracji do innych plików. Implementacja wspomnianej metody:

Tutaj wprowadzamy nasz tajny klucz, który służy do szyfrowania naszego tokena. Jak poprzednio, przechowuje go w pliku konfiguracyjnym. Definiujemy także to kto wystawia, oraz kto będzie konsumentem naszego tokena. Wszystko to w celu jak najlepszego zabezpieczenia naszej aplikacji.

Ostatnim etapem zabezpieczenia naszej aplikacji jest dodanie klasy, która będzie generowała nam nasze tokeny. Nie będę w całości kopiował tego kodu (kod dostępny w serwisie GitHub tutaj), a tylko kilka kluczowych elementów.

W sytuacji, gdy potwierdzimy tożsamość użytkownika, generujemy klucz, tak samo jak robiliśmy to podczas konfiguracji. Następnie przy pomocy algorytmu HmacSha256 będziemy szyfrować dane. Token zawiera podstawowe informacje o użytkowniku, a także zbiór jego uprawnień, Claims. Dokładniej o tym co zawiera taki token napiszę w innym poście, gdzie opowiem więcej o wspomnianych Claims.

Teraz wywołujemy tą klasę w kontrolerze i nasi użytkownicy mogą wysłać request o token.

Podsumowanie

Gdy przejdziemy przez kroki o których wspomniałem, otrzymamy gotowe rozwiązanie które pozwoli nam w pełni zabezpieczyć naszą aplikację. Nie wspomniałem tutaj o takich pojęciach jak np. CORS oraz SSL, ale myślę że będzie jeszcze ku temu okazja w kolejnych postach. Tymczasem zapraszam do komentowania oraz odwiedzenia mojego Twittera.