Integracja logowania do Facebooka w aplikacji AngularJS z Satelizerem

Opublikowany: 2022-03-11

Wraz z pojawieniem się bogatych w funkcje frameworków front-end, takich jak AngularJS, coraz więcej logiki jest wdrażanych na front-endzie, takich jak manipulacja/walidacja danych, uwierzytelnianie i inne. Satelizer, łatwy w użyciu moduł uwierzytelniania oparty na tokenach dla AngularJS, upraszcza proces implementacji mechanizmu uwierzytelniania w AngularJS, Biblioteka posiada wbudowaną obsługę Google, Facebook, LinkedIn, Twitter, Instagram, GitHub, Bitbucket, Yahoo, Twitch oraz konta Microsoft (Windows Live).

W tym artykule zbudujemy bardzo prostą aplikację internetową, podobną do tej tutaj, która pozwoli Ci się zalogować i zobaczyć informacje o aktualnym użytkowniku.

Uwierzytelnianie a autoryzacja

Są to 2 przerażające słowa, które często napotykasz, gdy Twoja aplikacja zaczyna integrować system użytkownika. Według Wikipedii:

Uwierzytelnianie to czynność polegająca na potwierdzeniu prawdziwości atrybutu pojedynczego fragmentu danych (danych), który jest potwierdzony przez jednostkę.

Autoryzacja to funkcja określania praw dostępu do zasobów związanych z bezpieczeństwem informacji i bezpieczeństwem komputerów w ogóle, aw szczególności z kontrolą dostępu.

W kategoriach laika weźmy przykład bloga, na którym pracują ludzie. Blogerzy piszą artykuły, a menedżer weryfikuje treść. Każda osoba może się uwierzytelnić (zalogować) do systemu, ale jej uprawnienia (autoryzacja) są inne, więc bloger nie może walidować treści, a menedżer może.

Dlaczego satelita

Możesz stworzyć własny system uwierzytelniania w AngularJS, wykonując kilka samouczków, takich jak ten bardzo szczegółowy: JSON Web Token Tutorial: przykład w Laravel i AngularJS. Proponuję przeczytać ten artykuł, ponieważ bardzo dobrze wyjaśnia JWT (JSON Web Token) i pokazuje prosty sposób na zaimplementowanie uwierzytelniania w AngularJS przy użyciu bezpośrednio lokalnego magazynu i przechwytujących HTTP.

Dlaczego więc Satelizer? Głównym powodem jest to, że obsługuje kilka loginów do sieci społecznościowych, takich jak Facebook, Twitter itp. W dzisiejszych czasach, szczególnie w przypadku witryn używanych na urządzeniach mobilnych, wpisywanie nazwy użytkownika i hasła jest dość uciążliwe, a użytkownicy oczekują, że będą mogli korzystać z Twojej witryny bez utrudnień za pomocą loginów społecznościowych. Ponieważ integracja SDK każdej sieci społecznościowej i śledzenie ich dokumentacji jest dość powtarzalne, byłoby miło obsługiwać te logowania społecznościowe przy minimalnym wysiłku.

Ponadto Satelizer jest aktywnym projektem na Github. Aktywny jest tutaj kluczowy, ponieważ te SDK zmieniają się dość często i nie chcesz od czasu do czasu czytać ich dokumentacji (każdy, kto pracuje z Facebook SDK, wie, jak to denerwujące)

Aplikacja AngularJS z logowaniem przez Facebook

Tu zaczyna się robić ciekawie.

Zbudujemy aplikację webową, która będzie miała mechanizm zwykłego logowania/rejestracji (tj. za pomocą nazwy użytkownika, hasła) oraz obsługuje logowanie społecznościowe. Ta aplikacja internetowa jest bardzo prosta, ponieważ ma tylko 3 strony:

  • Strona główna: każdy może zobaczyć
  • Strona logowania: aby wprowadzić nazwę użytkownika/hasło
  • Tajna strona: którą widzą tylko zalogowani użytkownicy

Do backendu użyjemy Pythona i Flask. Python i framework Flask są dość ekspresyjne, więc mam nadzieję, że przeniesienie kodu na inne języki/frameworki nie będzie bardzo trudne. Oczywiście do frontendu użyjemy AngularJS. A w przypadku logowania społecznościowego zintegrujemy się tylko z Facebookiem, ponieważ jest to obecnie najpopularniejsza sieć społecznościowa.

Zaczynajmy!

Krok #1: Projekt Bootstrap

Oto jak ustrukturyzujemy nasz kod:

 - app.py - static/ - index.html - app.js - bower.json - partials/ - login.tpl.html - home.tpl.html - secret.tpl.html

Cały kod zaplecza znajduje się w app.py . Kod frontonu jest umieszczany w folderze static/. Domyślnie Flask automatycznie wyświetla zawartość folderu static/. Wszystkie widoki częściowe znajdują się w static/partials/ i są obsługiwane przez moduł ui.router.

Aby rozpocząć kodowanie back-endu, będziemy potrzebować Pythona 2.7.* i zainstalować wymagane biblioteki za pomocą pip. Możesz oczywiście użyć virtualenv do wyizolowania środowiska Pythona. Poniżej znajduje się lista wymaganych modułów Pythona do umieszczenia w pliku Requirements.txt:

 Flask==0.10.1 PyJWT==1.4.0 Flask-SQLAlchemy==1.0 requests==2.7.0

Aby zainstalować wszystkie te zależności:

 pip install -r requirements.txt

W app.py mamy początkowy kod do ładowania Flask (instrukcje importu są pominięte dla zwięzłości):

 app = Flask(__name__) @app.route('/') def index(): return flask.redirect('/static/index.html') if __name__ == '__main__': app.run(debug=True)

Następnie uruchamiamy Bower i instalujemy AngularJS oraz ui.router :

 bower init # here you will need to answer some question. when in doubt, just hit enter :) bower install angular angular-ui-router --save # install and save these dependencies into bower.json

Po zainstalowaniu tych bibliotek, musimy dołączyć AngularJS i ui-router do index.html i utworzyć routing dla 3 stron: home, login i secret.

 <body ng-app="DemoApp"> <a ui-sref="home">Home</a> <a ui-sref="login">Login</a> <a ui-sref="secret">Secret</a> <div ui-view></div> <script src="bower_components/angular/angular.min.js"></script> <script src="bower_components/angular-ui-router/release/angular-ui-router.min.js"></script> <script src="main.js"></script> </body>

Poniżej znajduje się kod, którego potrzebujemy w main.js do konfiguracji routingu:

 var app = angular.module('DemoApp', ['ui.router']); app.config(function ($stateProvider, $urlRouterProvider) { $stateProvider .state('home', { url: '/home', templateUrl: 'partials/home.tpl.html' }) .state('secret', { url: '/secret', templateUrl: 'partials/secret.tpl.html', }) .state('login', { url: '/login', templateUrl: 'partials/login.tpl.html' }); $urlRouterProvider.otherwise('/home'); });

W tym momencie, jeśli uruchomisz serwer python app.py , powinieneś mieć ten podstawowy interfejs pod adresem http://localhost:5000

Podstawowy interfejs logowania

Linki Home, Login i Secret powinny działać w tym momencie i pokazywać zawartość odpowiednich szablonów.

Gratulacje, właśnie skończyłeś konfigurować szkielet! Jeśli napotkasz jakiś błąd, sprawdź kod na GitHub

Krok #2: Zaloguj się i zarejestruj

Pod koniec tego kroku będziesz mieć aplikację internetową, którą możesz zarejestrować/zalogować się za pomocą adresu e-mail i hasła.

Pierwszym krokiem jest konfiguracja backendu. Potrzebujemy modelu User oraz sposobu na wygenerowanie tokena JWT dla danego użytkownika. Przedstawiony poniżej model użytkownika jest naprawdę uproszczony i nie wykonuje nawet podstawowych kontroli, takich jak czy pole e-mail zawiera „@”, czy hasło do pola zawiera co najmniej 6 znaków itp.

 class User(db.Model): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(100), nullable=False) password = db.Column(db.String(100)) def token(self): payload = { 'sub': self.id, 'iat': datetime.utcnow(), 'exp': datetime.utcnow() + timedelta(days=14) } token = jwt.encode(payload, app.config['TOKEN_SECRET']) return token.decode('unicode_escape')

Używamy modułu jwt w pythonie do generowania części ładunku w JWT. Części iat i exp odpowiadają znacznikowi czasu utworzenia i wygaśnięcia tokenu. W tym kodzie token wygaśnie za 2 tygodnie.

Po utworzeniu modelu Użytkownika możemy dodać punkty końcowe „logowanie” i „rejestracja”. Kod dla obu jest dość podobny, więc tutaj pokażę tylko część „rejestr”. Należy pamiętać, że domyślnie Satelizer wywoła punkty końcowe /auth/login i /auth/signup odpowiednio dla „login” i „register”.

 @app.route('/auth/signup', methods=['POST']) def signup(): data = request.json email = data["email"] password = data["password"] user = User(email=email, password=password) db.session.add(user) db.session.commit() return jsonify(token=user.token())

Sprawdźmy najpierw punkt końcowy za pomocą curl:

 curl localhost:5000/auth/signup -H "Content-Type: application/json" -X POST -d '{"email":"[email protected]","password":"xyz"}'

Wynik powinien wyglądać tak:

 { "token": "very long string…." }

Teraz, gdy część back-endowa jest gotowa, zaatakujmy front-end! Najpierw musimy zainstalować satellizer i dodać go jako zależność w main.js:

 bower install satellizer --save

Dodaj satellizer jako zależność:

 var app = angular.module('DemoApp', ['ui.router', 'satellizer']);

Logowanie i rejestracja w satellizerze jest w rzeczywistości dość prosta w porównaniu do wszystkich dotychczasowych ustawień:

 $scope.signUp = function () { $auth .signup({email: $scope.email, password: $scope.password}) .then(function (response) { // set the token received from server $auth.setToken(response); // go to secret page $state.go('secret'); }) .catch(function (response) { console.log("error response", response); }) };

Jeśli masz jakiekolwiek trudności ze skonfigurowaniem kodu, możesz rzucić okiem na kod na GitHub.

Krok 3: Ale tajny widok nie jest tak naprawdę tajny, ponieważ każdy może go zobaczyć!

Tak to jest poprawne! Do tej pory każdy może wejść na tajną stronę bez logowania.

Czas dodać jakiś interceptor w AngularJS, aby mieć pewność, że jeśli ktoś przejdzie na tajną stronę i jeśli ten użytkownik nie jest zalogowany, zostanie przekierowany na stronę logowania.

Najpierw powinniśmy dodać flagę requiredLogin, aby odróżnić tajną stronę od innych.

 .state('secret', { url: '/secret', templateUrl: 'partials/secret.tpl.html', controller: 'SecretCtrl', data: {requiredLogin: true} })

Część „data” zostanie użyta w zdarzeniu $stateChangeStart, które jest uruchamiane przy każdej zmianie routingu:

 app.run(function ($rootScope, $state, $auth) { $rootScope.$on('$stateChangeStart', function (event, toState) { var requiredLogin = false; // check if this state need login if (toState.data && toState.data.requiredLogin) requiredLogin = true; // if yes and if this user is not logged in, redirect him to login page if (requiredLogin && !$auth.isAuthenticated()) { event.preventDefault(); $state.go('login'); } }); });

Teraz użytkownik nie może przejść bezpośrednio do tajnej strony bez zalogowania się. Hurra!

Jak zwykle kod tego kroku można znaleźć tutaj.

Krok 4: Nadszedł czas, aby uzyskać coś naprawdę tajnego!

W tej chwili na tajnej stronie nie ma nic naprawdę tajnego. Umieśćmy tam coś osobistego.

Ten krok rozpoczyna się od utworzenia punktu końcowego w zapleczu, który jest dostępny tylko dla uwierzytelnionego użytkownika, takiego jak posiadanie prawidłowego tokenu. Punkt końcowy /user poniżej zwraca identyfikator użytkownika i adres e- mail użytkownika odpowiadającego tokenowi .

 @app.route('/user') def user_info(): # the token is put in the Authorization header if not request.headers.get('Authorization'): return jsonify(error='Authorization header missing'), 401 # this header looks like this: “Authorization: Bearer {token}” token = request.headers.get('Authorization').split()[1] try: payload = jwt.decode(token, app.config['TOKEN_SECRET']) except DecodeError: return jsonify(error='Invalid token'), 401 except ExpiredSignature: return jsonify(error='Expired token'), 401 else: user_id = payload['sub'] user = User.query.filter_by(id=user_id).first() if user is None: return jsonify(error='Should not happen ...'), 500 return jsonify(id=user.id, email=user.email), 200 return jsonify(error="never reach here..."), 500

Ponownie używamy modułu jwt do dekodowania tokenu JWT zawartego w nagłówku „Authorization” i obsługi przypadku, gdy token wygasł lub nie jest ważny.

Przetestujmy ten punkt końcowy za pomocą curl. Najpierw musimy uzyskać ważny token:

 curl localhost:5000/auth/signup -H "Content-Type: application/json" -X POST -d '{"email":"[email protected]","password":"xyz"}'

Następnie za pomocą tego tokena:

 curl localhost:5000/user -H "Authorization: Bearer {put the token here}"

Co daje ten wynik:

 { "email": "[email protected]", "id": 1 }

Teraz musimy uwzględnić ten punkt końcowy w tajnym kontrolerze. Jest to dość proste, ponieważ wystarczy wywołać punkt końcowy za pomocą zwykłego modułu $http. Token jest automatycznie wstawiany do nagłówka przez Satellizera, więc nie musimy zawracać sobie głowy wszystkimi szczegółami dotyczącymi zapisania tokena, a następnie umieszczenia go w odpowiednim nagłówku.

 getUserInfo(); function getUserInfo() { $http.get('/user') .then(function (response) { $scope.user = response.data; }) .catch(function (response) { console.log("getUserInfo error", response); }) }

Wreszcie na tajnej stronie mamy coś naprawdę osobistego!

Tajna strona pokazująca adres e-mail i identyfikator użytkownika.

Kod tego kroku znajduje się na GitHub.

Krok #5: Zaloguj się na Facebooku za pomocą Satelizera

Zaletą Satelizera, jak wspomniano na początku, jest to, że znacznie ułatwia integrację logowania społecznościowego. Pod koniec tego kroku użytkownicy mogą zalogować się za pomocą swojego konta na Facebooku!

Uwierzytelnianie Facebook OAuth.

Pierwszą rzeczą do zrobienia jest stworzenie aplikacji na stronie deweloperów Facebooka, aby mieć identyfikator aplikacji i tajny kod. Wejdź na stronę developers.facebook.com/docs/apps/register, aby utworzyć konto programisty na Facebooku, jeśli jeszcze go nie masz, i utwórz aplikację internetową. Następnie będziesz mieć identyfikator aplikacji i sekret aplikacji, jak na poniższym zrzucie ekranu.

Uzyskiwanie sekretu aplikacji.

Gdy użytkownik zdecyduje się połączyć z Facebookiem, Satelizer wyśle ​​kod autoryzacyjny do punktu końcowego /auth/facebook . Za pomocą tego kodu autoryzacyjnego zaplecze może pobrać token dostępu z punktu końcowego Facebook /oauth , który umożliwia wywołanie interfejsu API Graph Facebooka w celu uzyskania informacji o użytkowniku, takich jak lokalizacja, znajomi_użytkownika, adres e-mail użytkownika itp.

Musimy również śledzić, czy konto użytkownika zostało utworzone na Facebooku, czy poprzez regularną rejestrację. W tym celu dodajemy facebook_id do naszego modelu użytkownika.

 facebook_id = db.Column(db.String(100))

Sekret Facebooka jest konfigurowany za pomocą zmiennych env FACEBOOK_SECRET, które dodajemy do app.config .

 app.config['FACEBOOK_SECRET'] = os.environ.get('FACEBOOK_SECRET')

Aby uruchomić app.py , powinieneś ustawić tę zmienną env:

 FACEBOOK_SECRET={your secret} python app.py

Oto metoda, która obsługuje logowanie na Facebooku. Satelizer domyślnie wywoła punkt końcowy /auth/facebook .

 @app.route('/auth/facebook', methods=['POST']) def auth_facebook(): access_token_url = 'https://graph.facebook.com/v2.3/oauth/access_token' graph_api_url = 'https://graph.facebook.com/v2.5/me?fields=id,email' params = { 'client_id': request.json['clientId'], 'redirect_uri': request.json['redirectUri'], 'client_secret': app.config['FACEBOOK_SECRET'], 'code': request.json['code'] } # Exchange authorization code for access token. r = requests.get(access_token_url, params=params) # use json.loads instead of urlparse.parse_qsl access_token = json.loads(r.text) # Step 2. Retrieve information about the current user. r = requests.get(graph_api_url, params=access_token) profile = json.loads(r.text) # Step 3. Create a new account or return an existing one. user = User.query.filter_by(facebook_id=profile['id']).first() if user: return jsonify(token=user.token()) u = User(facebook_id=profile['id'], email=profile['email']) db.session.add(u) db.session.commit() return jsonify(token=u.token())

Aby wysłać żądanie do serwera Facebooka, korzystamy z podręcznego modułu request. Teraz trudna część na zapleczu jest zakończona. Na froncie dodanie loginu do Facebooka jest dość proste. Najpierw musimy powiedzieć Satelizerowi nasz facebook_id , dodając ten kod do funkcji app.config :

 $authProvider.facebook({ clientId: {your facebook app id}, // by default, the redirect URI is http://localhost:5000 redirectUri: 'http://localhost:5000/static/index.html' });

Aby zalogować się za pomocą Facebooka, wystarczy zadzwonić:

 $auth.authenticate(“facebook”)

Jak zwykle możesz sprawdzić kod na GitHub

W tej chwili aplikacja internetowa jest kompletna pod względem funkcjonalności. Użytkownik może się zalogować/zarejestrować za pomocą zwykłego adresu e-mail i hasła lub za pomocą Facebooka. Po zalogowaniu użytkownik może zobaczyć swoją tajną stronę.

Zrób ładny interfejs

Interfejs nie jest w tym momencie zbyt ładny, więc dodajmy trochę Bootstrapa do układu i modułu kątowego tostera, aby dobrze obsłużyć komunikat o błędzie, na przykład w przypadku niepowodzenia logowania.

Kod tej części upiększającej znajdziesz tutaj.

Wniosek

W tym artykule przedstawiono krok po kroku integrację Satelizera z (prostą) aplikacją internetową AngularJS. Dzięki Satelizerowi możemy łatwo dodać inne loginy społecznościowe, takie jak Twitter, Linkedin i inne. Kod na stronie front-end jest taki sam jak w artykule. Jednak zaplecze różni się, ponieważ zestawy SDK sieci społecznościowych mają różne punkty końcowe z różnymi protokołami. Możesz zajrzeć na https://github.com/sahat/satellizer/blob/master/examples/server/python/app.py, który zawiera przykłady dla Facebooka, Github, Google, Linkedin, Twiter i Bitbucket. W razie wątpliwości powinieneś zapoznać się z dokumentacją na https://github.com/sahat/satellizer.

Powiązane: Logowanie jednym kliknięciem za pomocą Blockchain: samouczek MetaMask