Social-logowanie w .NET. Po co, dlaczego i jak?

16

Po dziś dzień standardowym “pierwszym krokiem” przy tworzeniu wielu aplikacji jest wygenerowanie tabeli Users z kolumnami Username i Password. Ewentualnie, jeśli ktoś jest bardziej wniknięty, to jeszcze Salt. Po co?

Jak to po co? Żeby dać użytkownikom możliwość zalogowania się do aplikacji, prawda? Czyli UWIERZYTELNIENIA. Ale… to chyba najgorszy możliwy sposób.

Dlaczego tego nie robić?

Czy jesteś w stanie zagwarantować, że Twoje dane są tak bezpieczne jak że aż bardzo bezpieczne?
Czy chcesz pisać masę kodu odpowiedzialną za ustawianie, resetowanie i przypominanie haseł?
Czy umiesz zaimplementować tzw. muti-factor authentication (czyli logowanie z pomocą jednorazowych generowanych haseł albo SMSów)?
Czy masz czas na radzenie sobie z niedocierającymi mailami?

Ja, pisząc aplikację prezentującą informacje o Uczestnikach Daj Się Poznać 2017 odpowiedziałem sobie szczerze: nie, nie, i nie. I jeszcze raz NIE.

Alternatywa

Przecież KTOŚ już to zrobił! Niejeden system zaimplementował to wszystko i ma rzesze ludzie dbających o to, by to działało. Ba, te systemy mają miliony użytkowników, na co dzień weryfikujących poprawność wszystkich tych mechanizmów. I ja mogłem tego użyć. Za friko.

W tym tekście przedstawiam krok po kroku “jak zaimplementować logowanie ‘social providerem’ w swojej aplikacji .NET“. Po więcej mięska, z tłem, teorią itd. odsyłam do podcasta: DevTalk#18 – O tożsamości z Tomaszem Onyszko. Bardzo polecam.

Wiele osób ma konto na Facebooku, Google, Twitterze czy MS Live. A jeśli targetujemy programistów to także na GitHub. Nie ma absolutnie żadnego sensu w wymyślaniu koła na nowo. I dodatkowo zmuszaniu ludzi do zakładania kolejnego konta w kolejnym miejscu w internecie.

Jak?

Poniżej w kilku prostych krokach dodamy możliwość uwierzytelnienia się w aplikacji .NETowej (webowej) poprzez Facebook, Google i GitHub. Tak jak można to zrobić na stronie DSP’17.

SimpleAuthentication

Po pierwsze: znajdujemy odpowiednią bibliotekę, która poradzi sobie z kodem infrastrukturalnym. Można to napisać samemu (robiłem to i polecam, fajna zabawa) ale raczej w hobbystycznie, a nie produkcyjnie. W .NET z pomocą przychodzi SimpleAuthentication (kiedyś: World Domination). Działa świetnie, gdy już poradzimy sobie z nienajlepszą dokumentacją i dość mylącymi “projekcikami pobocznymi”.

Wystarczy:

Install-Package SimpleAuthentication.Core

A potem połączenie z odpowiednim frameworkiem. W moim przypadku:

Install-Package SimpleAuthentication.Mvc4

Ewentualnie możemy dorzucić kilka dodatkowych “providerów”, tzw. “extrasów”. Na przykład integracja z GitHubem jest dostępna w tym pakiecie:

Install-Package SimpleAuthentication.ExtraProviders

Login URL

Strona zalogowania jest banalnie prosta, wystarczy wylistować listę wspieranych linków… i ewentualnie podpiąć je pod jakieś ikonki. Facebook będzie wyglądał tak:

<a href="@Url.RedirectToProvider("facebook")"><img src="/Content/social-img/facebook_32.png" alt="Login with your Facebook account." /></a>

I wsio. Wygeneruje to taki URL:

http://example.com/authentication/redirect/facebook

Obsługą tego żądania, odpowiednim redirectem, zajmie się już biblioteka. Użytkownik zostanie przekierowany na stronę Facebooka (albo innego providera), gdzie zaakceptuje co jest do zaakceptowania. A potem wróci do nas i musimy go przytulić, implementując interfejs IAuthenticationCallbackProvider. Przykłady znajdziesz tutaj, na WIKI. Albo poniżej (z tym że to nie robi niczego sensownego):

public class MyAuthenticationCallbackProvider : IAuthenticationCallbackProvider
{
    public ActionResult Process(HttpContextBase context, AuthenticateCallbackData model)
    {
        return new RedirectResult("/", true);
    }

    public ActionResult OnRedirectToAuthenticationProviderError(HttpContextBase context, string errorMessage)
    {
        return new RedirectResult("/", true);
    }
}

To jest moment, w którym otrzymujemy informację: “tak, to faktycznie jest ziomeczek posiadający konto na portalu X“. Dostaniemy też jakieś ID, username, czasami e-mail, czasami link do fotki… I musimy coś z tym zrobić.

CO zrobić? To zależy. Ja dodaję te dane do własnej bazki, by mieć “na później”. Prawdopodobnie przyda się też wygenerować cookie… czyli zaimplementować nad tym mechanizem normalne Forms Authentication. Ale to nie jest temat na dzisiaj.

Bo jeszcze nie koniec!

Social apps

Skąd Facebook, Google, GitHub czy Twitter wiedzą jaka strona żąda uwierzytelnienia? Z przesłanych tajnych wartości, tzw. “KEY” oraz “SECRET”. Wartości te generowane są dla APLIKACJI.

Chcesz umożliwić zalogowanie się u Ciebie przez Facebooka? Musisz pójść pod ten adres i stworzyć własną aplikację na Facebooku! GitHub? To będzie TUTAJ. A dla Google: TUTAJ.

Nadajemy własną nazwę, dorzucamy ikonkę. Ustawiamy “redirect URL”, czyli dokładny adres, pod którym nasza aplikacja czeka na zalogowanych userów. W moim przypadku, na przykład dla Google, jest to: http://uczestnicy.dajsiepoznac.pl/authentication/authenticatecallback?providerkey=google .

Uwaga: localhost nie wszędzie działa! I czasami można zdefiniować tylko jeden taki URL, więc najwygodniej jest po prostu od razu pchać to do testów na jakiś hosting, pod jakąś domenę.

Z ustawień aplikacji kopiujemy wygenerowane wartości KEY i SECRET i w jakiś sposób transportujemy je do własnego web.configa. Można je tam po prostu wkleić, ale wtedy trzeba uważać na pushe do publicznych repo :).

Kolejne kroki

Najlepsze w całej procedurze jest to, że to już wszystko. Koniec. F5 i działa.

Ktoś zapomniał hasła? Nie interesuje mnie to, hasła nie ma u mnie. Ktoś chce hasło zmienić? Niech idzie tam, gdzie je definiował. Wreszcie: z mojej aplikacji nastąpi wyciek danych? No szkoda, wstyd i w ogóle, ale… nikomu szkoda się nie stanie, bo nie przechowuję żadnych wrażliwych danych!

Polecam, zachęcam, pozdrawiam, całuję.

Share.

About Author

Programista, trener, prelegent, pasjonat, blogger. Autor podcasta programistycznego: DevTalk.pl. Jeden z liderów Białostockiej Grupy .NET i współorganizator konferencji Programistok. Od 2008 Microsoft MVP w kategorii .NET. Więcej informacji znajdziesz na stronie O autorze. Napisz do mnie ze strony Kontakt. Dodatkowo: Twitter, Facebook, YouTube.

16 Comments

  1. Fajny wpis.
    Niestety nie wszyscy mają konta na portalach, jak mają to mogą mieć akurat w takim, którego nie zaimplementowaliśmy, a nawet jeśli to mogą nie chcieć przekazywać dodatkowych danych (np. fotki). Wtedy mamy do wyboru – albo świadomie rezygnujemy z takich użytkowników (w przypadku DSP pewnie spokojnie można było tak zrobić), albo jednak implementujemy obsługę również u siebie. Wtedy zamiast robić to samemu, lepiej wykorzystać jeden z dostępnych frameworków, np. ASP.NET Identity Framework.

    • Michał,
      Właśnie chodzi o to żeby nie implementować tego “u siebie”.
      Tok rozumowania taki:
      1) user ma konto na socialach ale nie chce go “łączyć” albo nie ma kont na socialach
      2) user potrzebuje konta GDZIEŚ żeby korzystać z mojej aplikacji
      3) user MUSI założyć konto – co mu za różnica gdzie (czy u mnie czy na socialu) skoro będzie używał tego tylko do logowania do MOJEJ aplikacji?
      4) niech user założy nawet fejkowe konto gdzieś indziej, a nie u mnie, i się nim do mnie loguje

      Wszystkie cele osiągnięte: on się niczym ze mną nie dzieli, a ja nie muszę się babrać z obsługą tego u siebie.

    • Hej Michał,

      Jako że już mnie Maciek wywołał do tablicy trochę to odpowiem :) – nie, wtedy też nie musisz trzymać rzeczy u siebie albo przynajmniej nie robić tego samodzielnie, kilka alternatyw

      1. Bierzesz wspaniały projekt jakim jest Identity Server i implementujesz to w ramach swojego projektu. Wtedy oprócz tego wszystkiego co napisał Maciek masz też zapewnioną obsługę lokalnych kont (albo możesz ją sam zbudować) -> dalej, doczytaj -> https://github.com/IdentityServer
      2. Bierzesz na tapetę wspaniałą usługę jaką jest Auth0 – jest płatna ale … whoo hoo – do 7k userów jest free -> https://auth0.com/pricing zapewnia Ci też obsługę lokalnych kont itp.
      3. Lubisz dużych vendorów -> Azure AD B2C for rescue … I tutaj, nie umawialiśm się z Maćkiem ale akurat puściłem art w temacie u nas na blogu – http://predica.pl/blog/azure-ad-b2c-apps-for-consumers-in-the-cloud/ – do 50k ludzi za free.
      4. Nie lubisz Microsoft … Amazon for rescue … http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html
      5. Nie lubisz Microsot, Amazon powoduje u Ciebie wymioty … GOOGLE się tobą zaopiekuje :) – https://firebase.google.com/docs/auth/

      ….

      Jest jeszcze kilka innych rozwiązań :) i nie sprowadza się to tylko do obsługi logowania przez social ale też zabezpieczenia twoich API itp. Whoo hoo -> zabezpieczenie API trafiło na listę OWASP -> https://github.com/OWASP/Top10/blob/master/2017/OWASP%20Top%2010%20-%202017%20RC1-English.pdf

      Już kończę to linkowanie :)

      • Dzieki :)
        Tak, w nowym projekcie uzywam wlasnie IdentityServer + IdentityFramework (post coming ;)). Właśnie o to mi chodziło w ostatnim zdaniu, że lepiej nie robić tego samodzielnie :)

        A co do zmuszania usera do założenia konta gdzieś… Uważam, że nie wszędzie to przejdzie. Jeśli robisz produkt/usługę, którą chcesz sprzedawać, pewnie będziesz chciał mieć pełną kontrolę nad ‘flow’ użytkownika w rejestracji i optymalizować go tak, żeby mieć jak największą konwersję i sprzedaż. Wymuszanie zostawiania maila gdzieć trochę się z tym kłóci… Poza tym, nie każdy user będzie chciał to zrobić, a Ty w takim przypadku zdecydowanie chcesz każdego usera i jego $$$ ;)

        • Użycie zewnętrznego konta nie wyklucza tego, że u siebie przeprowadzasz go przez “flow” rejestracji i zebrania danych u siebie. W przypadku takiego Azure AD B2C możesz zrobić cuda niewidy używając czegoś co się nazywa advanced policy -> https://github.com/Azure-Samples/active-directory-b2c-advanced-policies

          Przykładowy scenariusz:
          1. User loguje się kontem “nie wiadomo skąd” (wiadomo, jeden z twoich idp)
          2. Grzecznie prosisz go o uzupełnienie profilu i zgodę na przetwarzanie danych. Zapisujesz to w GraphAPI
          3. Sprawdzasz czy masz już go w bazie swojego newsletter, jeżeli nie to pytasz się czy chce dostawać newsletter i jak często
          4. Pytasz się grzecznie o numer telefonu i potwierdzasz go kodem SMS
          5. Jak już to masz to pytasz się czy chce używać MFA i zaznaczasz decyzję w katalogu.

          I to wszystko obrandowoane pod twoją stronę.

    • Kamil Ławniczak on

      @Michal Dymalel z góry sorry ale niestety dtego typu wymówka, chaczy juz o złą wolę. I Na końcu wyjaśnię dlaczego i nie zamierzam użyć argumentów o pragmatyźmie. Najpierw jednak post.

      Ale przed jeszcze issue: Panie procencie czemu wciskam małpkę i muszę pisać pełne imię i nazwisko ? ??
      Czytelnicy upraszają się o imprułw komentarzy w sprintlogu :)

      Post:
      Racja, święta racja ale i gównoracja ponieważ:

      – Gdy widzę formularze do logowania i http przed adresem, usilnie upraszam o publikację lokalizacji. Atomówka sprawiedliwości już leci…

      – Do dziś pamiętam, jak najdalej 4 lat wstecz miałem taska “Improvement” polegającego na zabezpieczeniu stringów haseł w bazie danych, więcej nie trzeba…

      Naprawdę powiniśmy się wszyscy zastanowić, czy rozpatrywanie “Nie robienia własnej auoryzacji autentykacj i acji” ma tylko przesłanki pragmatyczne i usprawniające. W dziedzinie ochrony danych wrażliwych przepisy zaostrzają się coraz bardziej, a ich definicja będzie się tylko rozszerzać.

      Mogę dużo się nie mylić ale w skończonym czasie i to krótszym niż dłuższym, pojawią się w naszej branży regulacje. Być może między innymi będą koncesjonować usługi w zakresie dowożenia i utrzymywania funkcji bezpieczeństwa dla podmiotów wszelakich . O ile nie mamy doświadczonego i rozwijanego zespołu, który ma rozwiązanie utrzymywane i rozwijane przez lata, to nie mamy co startować do tego wyścigu.

      No ale zresolwujmy tamten kontekst i przyjmijmy, że oczywiście kto jak nie my.

      1. Ile czasu i cierpliwości naszych chlebodawców zajmie, zanim przed sobą, userami, biznesem, else, z czystym sercem przyznamy, ze nasze {coś} jest dostatecznie zabezpieczone.

      2. Jak wgl upewnimy się, ze jesteśmy bezpieczni, i ile czasu poświęcimy na wyczerpujące testy. Chyba nie zamockujesz certyfikatu klucza w unitach i stwierdzisz : Passed! `,’ Duju?

      3. Ile miejsc w systemie wymaga autoryzacji ? Czy Zmiany w około nich nie wywalą nam security testów? Mamy testy? ^

      4. A co jeśli biznes odwiedzi nas, z wiadomością, że lokalne GIODO wpadnie na audycik. Możemy spać spokojnie ? pewnie tak…

      5.No i na samym końcu: Skorzystanie z gotowca, nie tylko da wszystkie benefity opisane w poście, ale i uczyni łatwieszą i lepszą naszą część => ograniczanie dostępu do userom wynikajće z ewentualnych biznesowych przesłanek.

      Reasumująć:
      “Niektórzy krawaciarze chcą swój pasek logowania no i trzeba samemu…” uważam za naiwną wymówkę, gdyż odpowiedzialni i dojrzali devsi (wykluczamy tych rekinów z początku ;) ) przedstawiliby powyższe i tysiąc innych niebezpieczeństw tym ważnym, i nawet własnego paska zrobili by czyjegoś, uz widziałem, że ktoś wspomina o Auth0 choćby.

      Starałem się nie demonizować, ale jednocześne temat mnie mierzi i chciałem poruszyć trochę szersze jego spektrum. Jednym słowem rozparywanie kontekstu tylko od strony NIH, Pragmatyzmu, Szybkości posuwania się, uważam za niedopowiedzenie, a głęboko wpaść możemy. Zapraszam do polemiki JOŁ!!!!

  2. Za MFA placisz per-auth. Płacisz za auth usera nie za ilość social logins, które ma przypisane. Czyli – user może logować się FB/Google ale po zalogowaniu chcesz na nim wymusić MFA -> 0,03 USD. There is no free lunch jeżeli chodzi o Telco :).

  3. Krystian Kolad on

    To teraz wyczekiwać posta o Forms Authentication. Bardzo dobry content ;D Pozdrawiam

  4. tomaszk-poz on

    Takie rzeczy to można robić na publicznych portalach, mam system dla instytucji, gdzie ten numer nie przejdzie, bo a) użytkownicy nie muszą mieć FB/Google/Twittera b) firma może mieć awarię internetu i wtedy klops. Tak więc nie ma co tego przedstawiać jako coś cudownego, bo można wtopić. Poza tym np. ja jako mający konto google nie chciałbym, aby to konto było wiązane z jakimś serwisem, ja tam im nie ufam żadnej ze stron i nie chcę, że informacja gdzieś się plątała po internecie, wolę klasyczne rozwiązanie. Tak wiem, w tym tajnym serwisie mogą dziać się dziwne rzeczy, ale ja do tego mam inne hasło. :-)
    Poza tym jak napisali poprzednicy – jakieś płacenie, etc, albo płacenie w przyszłości albo likwidacja usługi – bez sensu.
    Poza tym chyba Microsoft ma swoją bibliotekę do logowania za pomocą społecznościówek (w którymś nowszym MVC) + federation services

    • Hej Tomasz,

      Tak jak napisałeś w większość przypadków, to dotyczy stron dla consumers. Wewnętrz firmy to wygląda inaczej a o takim rozwiązaniu piszesz jako rozwiązaniu u siebie (sądząc po tym braku internetu).

      Chociaż uwierz – to też się zmienia i coraz częściej częścią firmy jest ktoś, kto nigdy w tej firmie się nie pojawia i w zasadzie potrzebuje dostępu tylko do kilku rzeczy. I usługi pod to też się zmieniają – -taka dygresja.

      Maciek nie przedstawił tego jako cudownego rozwiązania ale jako rozwiazanie dla konkretnego problemu. Jeżeli nie aplikuje sie do twojej systuacji to OK, ale pomyśl – będziesz budował stronę dla zewnętrznych ludzi – dobrze wiedzieć, że tak się da :)! Prawda!

      Co do tego – “możesz wtopić”. To popatrzmy – ile razy jak dotąd w kwestii bezpieczeństwa wtopiły firmy takie jak FB, Google czy Microsoft (mówimy o bezpieczeństwie kont itp) a ile razy wtopiły aplikacje, w których ktoś postanowił obsłużyć to sam, Wyniik 0: do https://haveibeenpwned.com/ – to powinno dać trochę do myślenia.

      Jeżeli nie ufasz żadnej ze stron to nie korzystaj z google. Serio mówię. Oni dopiero powodują, że twoje dane plątają się w różnych miejscach – post bombing -> http://onyszko.com/2016/09/20/prywatnosc/.

      Co do meritum – po stronie Maćka nie plątają się twoje informacje a jedynie token wystawiony przez Google czy innego providera, który za dużo nie zawiera.

      Płacenie się pojawia bo ktoś utrzymuje to za Ciebie. Jeżeli usiadłbyś i porównał koszt to tak naprawdę jest on niższy niż gdybyś robił to sam, ale to wymaga policzenia nie tylko opłat bezpośrednich ale takich rzeczy jak twój wkład pracy, utrzymanie, zmiany, koszt potencjalnej wtopy, koszt SMS przy MFA – problem w wielu wypadkach jest taki, że przyrównujesz ten koszt do “0” (usiądę i napiszę). A to nie jest koszt “zero”.

      Co do biblioteki – tak, MS ma swoją bibliotekę ale ma też swoje usługi i bibliotkei do nich. Ta która sie teraz tworzy i ma być master of it all to MAL: https://github.com/AzureAD/microsoft-authentication-library-for-dotnet