Статьи

Добавить аутентификацию Twitter в приложение Ember.js с помощью Torii

Ember.js logo

Torii — это легкая библиотека аутентификации для Ember.js. Он поддерживает различных поставщиков OAuth (таких как Twitter, Google или FaceBook) и может использоваться для реализации всплывающего потока перенаправления OAuth. Он использует диспетчер сеансов (для поддержки текущего пользователя) и адаптеры (для сохранения состояния аутентификации).

В этой статье я покажу, как реализовать вход в Twitter и как обрабатывать пользовательские сеансы с помощью Torii. Twitter использует OAuth 1.0a для аутентификации, которая не требует особых настроек на стороне клиента (только всплывающее окно и управление сеансами). Однако для этого требуется значительный серверный компонент, для которого я буду использовать Sinatra.

Для желающих следовать, вы можете взять код, сопровождающий эту статью из GitHub .

Настройка приложения в Twitter

Если вы хотите следовать, вам также нужно настроить приложение в Twitter. Вы можете сделать это, перейдя на http://apps.twitter.com , где вы нажимаете «Создать новое приложение». После этого заполните свои данные, убедившись, что введите http://127.0.0.1:9292 в поле URL обратного вызова (при условии, что вы проводите локальное тестирование).

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

Настройка сервера

Это требует немного знаний о том, как работает OAuth 1.0a (если вы хотите освежиться, вы можете проверить документацию на сайте Twitter ). Это также требует библиотеки, которая поддерживает аутентификацию с различными поставщиками OAuth. Поскольку мы используем Sinatra, OmniAuth является отличным выбором (он основан на Rack, поэтому будет работать практически во всех веб-приложениях на Ruby). Если бы мы использовали Node, мы могли бы вместо этого выбрать Passport .

Вместо того, чтобы просматривать настройки сервера, вы можете просто взять рабочую копию приложения и загрузить ее самостоятельно. Вот как:

 git clone https://github.com/sitepoint-editors/torii-twitter-example.git cd torii-twitter-example 

Затем в своем терминале добавьте свой ключ потребителя и свой секрет потребителя в свою среду

 export TWITTER_KEY=twitter_key TWITTER_SECRET=twitter_secret 

Запустите bundle для установки любых зависимостей (предполагается, что у вас установлен Ruby), затем rake db:migrate для настройки базы данных.

После этого вам нужно собрать приложение Ember:

 cd public npm install && bower install ember build 

Наконец, запустите rackup чтобы запустить Sinatra и перейти к http://127.0.0.1:9292 . Если все прошло по плану, вы сможете войти в свое новое приложение через Twitter.

Обратите внимание, что конечные точки сервера:

Неаутентифицированный пользователь:

  • get '/auth/twitter' : запускает вход в систему, запрашивает токен из Twitter, перенаправляет пользователя в Twitter для аутентификации.
  • get '/auth/twitter/callback' : Twitter аутентифицирует и отправляет токен здесь, сервер обменивает токен на токен доступа и аутентифицирует пользователя.

Аутентифицированный пользователь:

  • post '/logout' : очищает аутентификацию пользователя.
  • get '/users/me' : возвращает аутентифицированную информацию о пользователе.

Теперь давайте используем наше приложение, чтобы посмотреть, как вы можете реализовать Torii в своих собственных проектах.

Установить тории

Сначала настройте проект Ember с Ember CLI и установите Torii (наш установлен в public папке):

 ember init npm install –save-dev torii 

Настройте провайдера

Затем добавьте провайдера Twitter и установите requestTokenUri к конечной точке сервера, с которой начинается поток: /auth/twitter . Также установите sessionServiceName: 'session' для настройки менеджера сеансов.

config/environment.js

 ENV.torii = { sessionServiceName: 'session', providers: { 'twitter': { requestTokenUri: '/auth/twitter' } } }; 

В Torii есть несколько встроенных провайдеров , но создание собственного разработано очень просто.

Войти в систему

Далее настройте шаблон входа в систему. Если пользователь прошел аутентификацию, покажите его имя и ссылку для выхода. Если они не аутентифицированы, покажите ссылку для входа. Имеет смысл поместить это в шаблон application чтобы он был виден на каждом маршруте.

app/templates/application.hbs

 {{#if session.isWorking }} Working.. {{else}} {{#if session.isAuthenticated }} <p>Welcome {{session.currentUser.name}} <a href="#" {{action 'logout'}}>Logout</a> </p> {{else}} <a href="#" {{action 'signInViaTwitter'}}>Login via Twitter</a> {{/if}} {{/if}} 

Свойство session внедряется менеджером сеансов Torri и предоставляет несколько полезных свойств. session.isWorking имеет значение true между такими переходами состояния, как opening для authenticated или closing для unauthenticated . Не используйте session между переходами, но вместо этого показывайте полосу загрузки. session.currentUser является аутентифицированным пользователем — он устанавливается адаптером.

Затем определите действие signInViaTwitter которое откроет всплывающее окно и запустит знак OAuth в потоке.

app/routes/login.js

 actions: { signInViaTwitter: function() { var route = this; this.get('session').open('twitter').then(function() { route.transitionTo('index'); }, function() { console.log('auth failed'); }); } } 

Обратите внимание, что this.get('session').open('twitter') возвращает обещание, которое разрешается после аутентификации пользователя, которое, в свою очередь, закрывает всплывающее окно и устанавливает сеанс. Как только пользовательский сеанс установлен, он переходит на индексный маршрут, тогда как, если он терпит неудачу, он ничего не делает.

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

app/routes/application.js

 export default Ember.Route.extend({ beforeModel: function() { return this.get('session').fetch().then(function() { console.log('session fetched'); }, function() { console.log('no session to fetch'); }); }, actions: { logout: function() { this.get('session').close(); } } }); 

Здесь this.get('session').fetch() выбирает существующий сеанс и устанавливает пользователя как аутентифицированного. Мы beforeModel это в хук beforeModel так что приложение будет ждать, пока пользователь не будет извлечен, перед рендерингом. Как и следовало ожидать, this.get('session').close() закрывает сессию, что происходит, когда пользователь нажимает «Logout».

Управление сессиями и адаптер

Адаптер Torii обрабатывает проверку подлинности сервера и управляет сеансом пользователя тремя способами: open , fetch и close . Они идут в папке app/torii-adapters . По умолчанию используется адаптер приложения, который расширяет Ember.Object .

Метод open создает сеанс. Это происходит, когда наш сервер отправляет маркер аутентификации в приложение Ember (посредством перенаправления всплывающего окна) с параметром code , например /?code=authentication_code . Этот code анализируется Torii и передается нашему адаптеру в параметре auth . Чтобы кратко описать поток:

  1. Torii открывает всплывающее окно в /auth/twitter .
  2. Сервер перенаправляет на Twitter.
  3. Пользователь аутентифицируется с помощью Twitter.
  4. Twitter перенаправляет на /auth/twitter/callback .
  5. Сервер аутентифицирует пользователя и генерирует токен доступа.
  6. Сервер перенаправляет на наше приложение Ember с токеном доступа, например: /?code=access_token
  7. Torii закрывает всплывающее окно, анализирует код и передает его адаптеру.

Как только токен становится доступным, он помещается в локальное хранилище и устанавливается заголовок авторизации для запросов Ajax. Аутентифицированный пользователь извлекается путем отправки запроса Ajax users/me и сохраняется в сеансе.

app/torii-adapters/application.js

 open: function(auth) { if (!auth.code) { return rejectPromise(); } localStorage.token = auth.code; var adapter = this.container.lookup('adapter:application'); adapter.set('headers', { 'Authorization': localStorage.token }); return this.get('store').find('user', 'me').then(function(user) { return { currentUser: user }; }); }, 

Параметр auth содержит код — если он недоступен, обещание отклоняется и проверка подлинности не выполняется. Чтобы установить заголовки для Ember Data, используйте this.container.lookup чтобы найти adapter:application и установить заголовки для этого адаптера. this.get('store').find('user', 'me') отправляет запрос users/me , прежде чем объект со свойством currentUser (установленным для аутентифицированного пользователя) будет возвращен. Torii добавит это к объекту session который он будет внедрять во все маршруты, чтобы он был доступен в шаблонах.

Примечание : вам нужно определить пользовательскую модель с Ember CLI, чтобы сделать запрос к конечной точке users/me с Ember Data:

ember g model user name:string token:string

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

 fetch: function() { if (!localStorage.token) { return rejectPromise(); } var adapter = this.container.lookup('adapter:application'); adapter.set('headers', { 'Authorization': localStorage.token }); return this.get('store').find('user', 'me').then(function(user) { return { currentUser: user }; }); }, 

Метод получения аутентифицированного пользователя с токеном — это выборка пользователя из users/me . Тории не знает, как вести сеансы, если вы предоставляете логику через ловушки адаптера. Пожалуйста, не стесняйтесь поделиться любыми альтернативными методами, которые у вас могут быть.

Наконец, метод close закрывает сессию. Он удаляет токен из локального хранилища и post /logout Ajax-запрос на post /logout на сервер, что делает маркер доступа недействительным.

 close: function() { var authToken = localStorage.token; localStorage.token = null; var adapter = this.container.lookup('adapter:application'); adapter.set('headers', { 'Authorization': authToken }); return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ url: '/logout', headers: { 'Authorization': authToken }, type: 'POST', success: Ember.run.bind(null, resolve), error: Ember.run.bind(null, reject) }); }); } 

Вывод

Мне потребовалось некоторое время, чтобы понять, как должна работать аутентификация для одностраничного приложения, не говоря уже о том, как работает OAuth. Это особенно верно, если приложение взаимодействует с REST API, который, как предполагается, не имеет состояния и, таким образом, не доступен сеанс на стороне сервера для сохранения пользователя. Поэтому я предпочитаю аутентификацию на основе токенов. Ember, к сожалению, не хватает в таких уроках, поэтому, если вы хотите узнать больше, вы должны искать другие фреймворки, такие как AngularJS.

Вот еще кое-что, что вы можете найти полезным: