Аутентификация в приложениях AngularJS с помощью Satellizer

  1. Почему сателлизатор
  2. Шаг № 1: Проект начальной загрузки
  3. Шаг № 3: Но секретный взгляд не является действительно секретным, потому что каждый может его увидеть!
  4. Шаг № 4: Пора получить что-то действительно секретное!
  5. Сделать симпатичный интерфейс
  6. Заключение

С появлением многофункциональных интерфейсных сред, таких как AngularJS, все больше и больше логики реализуется на внешнем интерфейсе, например, манипулирование данными / проверка, аутентификация и многое другое. Satellizer, простой в использовании модуль аутентификации на основе токенов для AngularJS, упрощает процесс внедрения механизма аутентификации в AngularJS. Библиотека поставляется со встроенной поддержкой Google, Facebook, LinkedIn, Twitter, Instagram, GitHub, Bitbucket, Yahoo, Twitch. и учетные записи Microsoft (Windows Live).

В этой статье мы создадим очень простое веб-приложение, похожее на Вот который позволяет вам войти и увидеть информацию о текущем пользователе.

Это два страшных слова, с которыми вы часто сталкиваетесь, когда ваше приложение начинает интегрировать пользовательскую систему. Согласно Википедии:

Аутентификация - это акт подтверждения истинности атрибута отдельного фрагмента данных (данных), который является истинным для объекта.

Авторизация - это функция указания прав доступа к ресурсам, связанным с информационной безопасностью и компьютерной безопасностью в целом, а также с контролем доступа в частности.

С точки зрения непрофессионала, давайте возьмем пример веб-сайта блога с некоторыми людьми, работающими над этим. Блоггеры пишут статьи, а менеджер проверяет контент. Каждый человек может проходить аутентификацию (вход в систему) в систему, но его права (авторизация) различны, поэтому блоггер не может проверять контент, а менеджер может.

Почему сателлизатор

Вы можете создать свою собственную систему аутентификации в AngularJS, следуя некоторым учебникам, таким как этот очень подробный: Учебник по веб-токену JSON: пример в Laravel и AngularJS , Я предлагаю прочитать эту статью, так как она очень хорошо объясняет JWT (JSON Web Token) и показывает простой способ реализации аутентификации в AngularJS с использованием непосредственно локального хранилища и перехватчиков HTTP.

Так почему сателлизатор? Основная причина в том, что он поддерживает несколько входов в социальные сети, таких как Facebook, Twitter и т. Д. В настоящее время, особенно для веб-сайтов, используемых на мобильных устройствах, ввод имени пользователя и пароля довольно громоздкий, и пользователи ожидают, что смогут использовать ваш сайт с небольшими помехами. используя социальные логины. Поскольку интеграция SDK каждой социальной сети и следование их документации довольно повторяющиеся, было бы неплохо поддерживать эти социальные логины с минимальными усилиями.

Более того, Satellizer - это активный проект на Github. Активный - это ключевой момент, так как эти SDK меняются довольно часто, и вы не хотите время от времени читать их документацию (любой, кто работает с Facebook SDK, знает, насколько это раздражает)

Здесь вещи начинают становиться интересными.

Мы создадим веб-приложение с обычным механизмом входа / регистрации (т. Е. С использованием имени пользователя и пароля), а также с поддержкой социальных входов. Это веб-приложение очень просто, так как в нем всего 3 страницы:

  • Домашняя страница: каждый может увидеть
  • Страница входа: для ввода имени пользователя / пароля
  • Секретная страница: которую могут видеть только зарегистрированные пользователи

Для бэкэнда мы будем использовать Python и Flask. Python и фреймворк Flask довольно выразительны, поэтому я надеюсь, что перенос кода на другие языки / фреймворки не будет очень сложным. Мы, конечно, будем использовать AngularJS для фронт-энда. А для социальных входов мы будем интегрироваться только с Facebook, так как это самая популярная социальная сеть в настоящее время.

Давайте начнем!

Шаг № 1: Проект начальной загрузки

Вот как мы будем структурировать наш код:

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

Весь внутренний код находится в app.py. Код внешнего интерфейса помещается в папку static /. По умолчанию Flask автоматически подает содержимое static / folder. Все частичные представления находятся в static / partials / и обрабатываются модулем ui.router.

Чтобы начать писать код, нам понадобится Python 2.7. * И установить необходимые библиотеки с помощью pip. Конечно, вы можете использовать virtualenv для изоляции среды Python. Ниже приведен список необходимых модулей Python, которые нужно поместить в файл require.txt:

Flask == 0.10.1 PyJWT == 1.4.0 Flask-SQLAlchemy == 1.0 запросов == 2.7.0

Чтобы установить все эти зависимости:

pip install -r needs.txt

В app.py у нас есть некоторый исходный код для начальной загрузки Flask (операторы import для краткости опущены):

app = Flask (__ name__) @ app.route ('/') def index (): вернуть flask.redirect ('/ static / index.html'), если __name__ == '__main__': app.run (debug = True)

Далее мы запускаем bower и устанавливаем AngularJS и ui.router:

bower init # здесь вам нужно будет ответить на несколько вопросов. если сомневаетесь, просто нажмите enter :) bower install angular-ui-router - сохраните # install и сохраните эти зависимости в bower.json

После установки этих библиотек нам нужно включить AngularJS и ui-router в index.html и создать маршрутизацию для 3 страниц: home, login и secret.

<body ng-app = "DemoApp"> <a ui-sref="home"> Главная страница </a> <a ui-sref="login"> Вход </a> <a ui-sref="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>

Ниже приведен код, который нам нужен в main.js для настройки маршрутизации:

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');});

На этом этапе, если вы запустите сервер python app.py , вы должны иметь этот базовый интерфейс в HTTP: // локальный: 5000

py , вы должны иметь этот базовый интерфейс в   HTTP: // локальный: 5000

Ссылки Home, Login и Secret должны работать на этом этапе и отображать содержимое соответствующих шаблонов.

Поздравляем, вы только что закончили настройку скелета! Если вы столкнулись с какой-либо ошибкой, пожалуйста, проверьте код на GitHub

В конце этого шага у вас будет веб-приложение, которое вы можете зарегистрировать / войти, используя электронную почту и пароль.

Первым шагом является настройка бэкэнда. Нам нужна модель User и способ генерирования токена JWT для данного пользователя. Модель пользователя, показанная ниже, действительно упрощена и не выполняет даже каких-либо базовых проверок, например, содержит ли поле электронной почты «@», или если поле пароля содержит не менее 6 символов и т. Д.

класс User (db.Model): id = db.Column (db.Integer, primary_key = True) email = db.Column (db.String (100), nullable = False) пароль = 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']) возвращает token.decode ('unicode_escape')

Мы используем модуль jwt в python для генерации части полезной нагрузки в JWT. Части iat и exp соответствуют метке времени, когда токен был создан и истек. В этом коде срок действия токена истекает через 2 недели.

После того, как модель User была создана, мы можем добавить конечные точки «login» и «register». Код для обоих очень похож, поэтому здесь я просто покажу часть «регистрация». Обратите внимание, что по умолчанию Satellizer вызывает конечные точки / auth / login и / auth / signup для «login» и «register» соответственно.

@ app.route ('/ auth / signup', method = ['POST']) def signup (): data = request.json email = data ["email"] пароль = data ["пароль"] user = User ( электронная почта = электронная почта, пароль = пароль) db.session.add (пользователь) db.session.commit () return jsonify (token = user.token ())

Давайте сначала проверим конечную точку, используя curl:

curl localhost: 5000 / auth / signup -H "Тип контента: приложение / json" -X POST -d '{"электронная почта": " [электронная почта защищена] », "Пароль": "хуг"}»

Результат должен выглядеть так:

{"жетон": "очень длинная строка ..." }

Теперь, когда серверная часть готова, давайте атаковать ее! Во-первых, нам нужно установить satellizer и добавить его в качестве зависимости в main.js:

Бауэр установить сателлитер - сохранить

Добавить сателлитер как зависимость:

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

Вход и регистрация в сателлитере на самом деле довольно прост по сравнению со всеми настройками до сих пор:

$ scope.signUp = function () {$ auth .signup ({электронная почта: $ scope.email, пароль: $ scope.password}) .then (function (response) {// установить токен, полученный от сервера $ auth.setToken (ответ); // перейти на секретную страницу $ state.go ('secret');}) .catch (function (response) {console.log ("error response", response);})};

Если у вас возникли трудности с настройкой кода, вы можете взглянуть на код на GitHub ,

Шаг № 3: Но секретный взгляд не является действительно секретным, потому что каждый может его увидеть!

Да, это правильно! До сих пор любой желающий может перейти на секретную страницу без входа в систему.

Пришло время добавить некоторый перехватчик в AngularJS, чтобы убедиться, что если кто-то перейдет на секретную страницу и если этот пользователь не вошел в систему, они будут перенаправлены на страницу входа.

Во-первых, мы должны добавить флаг requiredLogin, чтобы отличить секретную страницу от других.

.state ('secret', {url: '/ secret', templateUrl: 'partials / secret.tpl.html', контроллер: 'SecretCtrl', data: {requiredLogin: true}})

Часть «данные» будет использоваться в событии $ stateChangeStart, которое запускается при каждом изменении маршрутизации:

app.run (function ($ rootScope, $ state, $ auth) {$ rootScope. $ on ('$ stateChangeStart', function (event, toState) {var requiredLogin = false; // проверить, требуется ли этому состоянию вход в систему if (toState) .data && toState.data.requiredLogin) requiredLogin = true; // если да и если этот пользователь не вошел в систему, перенаправьте его на страницу входа if (requiredLogin &&! $ auth.isAuthenticated ()) {event.preventDefault (); $ state.go ('login');}});});

Теперь пользователь не может перейти непосредственно на секретную страницу без входа в систему. Ура!

Как обычно, код этого шага можно найти Вот ,

Шаг № 4: Пора получить что-то действительно секретное!

На данный момент в секретной странице нет ничего действительно секретного. Давайте положим что-то личное там.

Этот шаг начинается с создания конечной точки в серверной части, которая доступна только для аутентифицированного пользователя, например, имеющего действительный токен. Конечная точка / пользователь ниже возвращает идентификатор_пользователя и адрес электронной почты пользователя, соответствующего токену.

@ app.route ('/ user') def user_info (): # токен помещается в заголовок авторизации, если не request.headers.get ('авторизация'): возвращать jsonify (ошибка = 'отсутствует заголовок авторизации'), 401 # этот заголовок выглядит следующим образом: «Authorization: Bearer {token}» token = request.headers.get ('Authorization'). split () [1] try: payload = jwt.decode (token, app.config ['TOKEN_SECRET ']) кроме DecodeError: возвращать jsonify (error =' Invalid token '), 401 кроме ExpiredSignature: возвращать jsonify (error =' Expired token '), 401 else: user_id = payload [' sub '] user = User.query.filter_by (id = user_id) .first () если пользователь None: вернуть jsonify (ошибка = 'не должно произойти ...'), 500 вернуть jsonify (id = user.id, email = user.email), 200 вернуть jsonify ( error = "никогда сюда не доберёшься ..."), 500

Опять же, мы используем модуль jwt для декодирования токена JWT, включенного в заголовок «Авторизация», и для обработки случая, когда токен истек или недействителен.

Давайте проверим эту конечную точку, используя curl. Во-первых, нам нужно получить действительный токен:

curl localhost: 5000 / auth / signup -H "Тип контента: приложение / json" -X POST -d '{"электронная почта": " [электронная почта защищена] », "Пароль": "хуг"}»

Тогда с этим токеном:

curl localhost: 5000 / user -H "Авторизация: Носитель {поместите токен здесь}"

Который дает этот результат:

{ "Эл. адрес": " [электронная почта защищена] "," id ": 1}

Теперь нам нужно включить эту конечную точку в секретный контроллер. Это довольно просто, поскольку нам просто нужно вызвать конечную точку с помощью обычного модуля $ http. Токен автоматически вставляется в заголовок Satellizer, поэтому нам не нужно беспокоиться обо всех деталях сохранения токена, а затем поместить его в правильный заголовок.

GetUserInfo (); function getUserInfo () {$ http.get ('/ user') .then (function (response) {$ scope.user = response.data;}) .catch (function (response) {console.log ("ошибка getUserInfo" , ответ); }) }

Наконец, у нас есть что-то действительно личное на секретной странице!

Код этого шага включен GitHub ,

Хорошая вещь о Satellizer, как уже упоминалось в начале, заключается в том, что он значительно упрощает интеграцию в систему. В конце этого шага пользователи могут войти, используя свою учетную запись Facebook!

В конце этого шага пользователи могут войти, используя свою учетную запись Facebook

Первое, что нужно сделать, это создать приложение на странице разработчиков Facebook, чтобы иметь application_id и секретный код. Пожалуйста, следуйте developers.facebook.com/docs/apps/register создать учетную запись разработчика Facebook, если у вас ее еще нет, и создать приложение для веб-сайта. После этого у вас будет идентификатор приложения и секрет приложения, как на скриншоте ниже.

После этого у вас будет идентификатор приложения и секрет приложения, как на скриншоте ниже

Как только пользователь выберет соединение с Facebook, Satellizer отправит код авторизации на конечную точку / auth / facebook . С помощью этого кода авторизации серверная часть может получить токен доступа из конечной точки Facebook / oauth, который позволяет обращаться к API Graph Facebook для получения информации о пользователе, такой как местоположение, user_friends, электронная почта пользователя и т. Д.

Нам также необходимо отслеживать, создана ли учетная запись пользователя с помощью Facebook или посредством обычной регистрации. Для этого мы добавляем facebook_id к нашей модели User.

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

Секрет facebook настраивается через переменные env FACEBOOK_SECRET, которые мы добавляем в app.config .

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

Итак, чтобы запустить app.py , вы должны установить эту переменную env:

FACEBOOK_SECRET = {ваш секрет} python app.py

Вот метод, который обрабатывает логины Facebook. По умолчанию Satellizer будет вызывать конечную точку / auth / facebook .

@ app.route ('/ auth / facebook', method = ['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, электронная почта 'params = {' client_id ': request.json [' clientId '],' redirect_uri ': request.json [' redirectUri '], 'client_secret': app.config ['FACEBOOK_SECRET'], 'code': request.json ['code']} # Код авторизации Exchange для токена доступа. r = reports.get (access_token_url, params = params) # использовать json.loads вместо urlparse.parse_qsl access_token = json.loads (r.text) # Шаг 2. Получить информацию о текущем пользователе. r = orders.get (graph_api_url, params = access_token) profile = json.loads (r.text) # Шаг 3. Создайте новую учетную запись или верните существующую. user = User.query.filter_by (facebook_id = profile ['id']). first () если user: return jsonify (token = user.token ()) u = пользователь (facebook_id = profile ['id'], email = профиль ['email']) db.session.add (u) db.session.commit () return jsonify (token = u.token ())

Для отправки запроса на сервер Facebook мы используем удобный модуль запросов. Теперь трудная часть на заднем плане закончена. На переднем крае добавить логин на Facebook довольно просто. Во-первых, нам нужно сообщить Satellizer наш facebook_id , добавив этот код в функцию app.config :

$ authProvider.facebook ({clientId: {идентификатор вашего приложения Facebook}, // по умолчанию URI перенаправления имеет вид http: // localhost: 5000 redirectUri: 'http: // localhost: 5000 / static / index.html'}) ;

Чтобы войти через Facebook, мы можем просто позвонить:

$ Auth.authenticate ( «facebook»)

Как обычно, вы можете проверить код на GitHub

На данный момент веб-приложение полностью функционально. Пользователь может войти / зарегистрироваться, используя обычную электронную почту и пароль или используя Facebook. После входа в систему пользователь может увидеть свою секретную страницу.

Сделать симпатичный интерфейс

На данный момент интерфейс не очень приятный, поэтому давайте добавим немного Bootstrap для макета и модуль углового тостера для удобной обработки сообщения об ошибке, например, при сбое входа в систему.

Код для этой украшающей части можно найти Вот ,

Заключение

В этой статье описана пошаговая интеграция Satellizer в (простое) веб-приложение AngularJS. С помощью Satellizer мы можем легко добавлять другие социальные учетные записи, такие как Twitter, Linkedin и другие. Код на переднем конце такой же, как в статье. Однако серверная часть варьируется, поскольку SDK для социальных сетей имеют разные конечные точки с разными протоколами. Вы можете взглянуть на https://github.com/sahat/satellizer/blob/master/examples/server/python/app.py, который содержит примеры для Facebook, Github, Google, Linkedin, Twiter и Bitbucket. Если вы сомневаетесь, вы должны взглянуть на документацию по https://github.com/sahat/satellizer ,

Так почему сателлизатор?
Me?