Last active
February 3, 2017 11:54
-
-
Save izelnakri/4a3ed3135cd4700871406a6fec229553 to your computer and use it in GitHub Desktop.
Ember.js token based authentication without a library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| import config from '../config/environment'; | |
| import fetch from 'ember-network/fetch'; | |
| const { Service, inject, RSVP } = Ember; | |
| export default Service.extend({ | |
| store: inject.service(), | |
| authenticationToken: undefined, | |
| currentUser: undefined, | |
| fetchCurrentUser() { | |
| return new RSVP.Promise((resolve, reject) => { | |
| if (this.get('authenticationToken')) { | |
| return fetch(`${config.apiHost}/me`, { | |
| method: 'GET', | |
| mode: 'cors', | |
| headers: { | |
| 'Authorization': this.get('authenticationToken') ? | |
| `Token ${this.get('authenticationToken')}` : undefined | |
| } | |
| }).then((response) => { | |
| if (response.status === 200) { | |
| return response.json(); | |
| } | |
| return reject(); | |
| }).then((json) => { | |
| if (json.id) { // unfortunate need due to the fetch() function | |
| this.get('store').pushPayload({ user: json }); | |
| this.set('currentUser', this.get('store').peekRecord('user', json.id)); | |
| if (Raven) { | |
| Raven.setUserContext({ user_id: this.get('currentUser.id') }); | |
| } | |
| return resolve(this.get('currentUser')); | |
| } | |
| return reject(); // unfortunate need due to the fetch() function | |
| }).catch(() => { | |
| return reject(); // unfortunate need due to the fetch() function | |
| }); | |
| } | |
| return reject(); | |
| }); | |
| }, | |
| login(authenticationToken) { | |
| return new RSVP.Promise((resolve, reject) => { | |
| this.set('authenticationToken', authenticationToken); | |
| this.fetchCurrentUser().then((user) => { | |
| localStorage.setItem('yourapp_authentication_token', authenticationToken); | |
| return resolve(user); | |
| }).catch(() => { | |
| return reject(); | |
| }); | |
| }); | |
| }, | |
| logout() { | |
| return new RSVP.Promise((resolve, reject) => { | |
| if (this.get('currentUser')) { | |
| localStorage.removeItem('yourapp_authentication_token'); | |
| this.set('authenticationToken', null); | |
| this.set('currentUser', null); | |
| return resolve(); | |
| } | |
| return reject(); | |
| }); | |
| } | |
| }); | |
| // routes/application.js | |
| // this ensures the /me gets loaded before app goes to other route model()'s: | |
| import Ember from 'ember'; | |
| const { Route } = Ember; | |
| export default Route.extend({ | |
| model() { | |
| if (window && window.localStorage) { // ember fastboot edit | |
| this.get('session').set( | |
| 'authenticationToken', localStorage.getItem('yourapp_authentication_token') | |
| ); | |
| return this.get('session').fetchCurrentUser().then(() => { | |
| return; // finally() doesn't work somehow, Bluebird > Ember.RSVP | |
| }).catch(() => { | |
| return; | |
| }); | |
| } | |
| } | |
| }); | |
| // routes/base.js | |
| // you can call login() and logout functions throughout the app route and controller functions: | |
| // it needs ember-route-action-helper package | |
| // like: this.send('login', model.get('authenticationToken')); | |
| import Ember from 'ember'; | |
| import ScrollResetMixin from 'frontend/mixins/scroll-reset'; | |
| export default Ember.Route.extend(ScrollResetMixin, { | |
| actions: { | |
| login(authenticationToken) { | |
| this.get('session').login(authenticationToken).then((user) => { | |
| if (user.isAdmin) { | |
| return this.transitionTo('admin.index'); | |
| } | |
| return this.transitionTo('public.profile'); | |
| }); | |
| }, | |
| logout() { | |
| this.get('session').logout().then(() => { | |
| this.transitionTo('public'); | |
| }); // maybe a flashMessage | |
| } | |
| } | |
| }); | |
| // initializers/session.js | |
| // to make this.get('session') available everywhere: | |
| export default { | |
| name: 'session', | |
| after: 'ember-data', | |
| initialize(app) { | |
| app.inject('route', 'session', 'service:session'); | |
| app.inject('controller', 'session', 'service:session'); | |
| app.inject('application', 'session', 'service:session'); | |
| app.inject('component', 'session', 'service:session'); | |
| } | |
| }; | |
| // adapters/application.js | |
| // to ensure that we send the authenticationToken for Ember Data requests: | |
| import config from 'frontend/config/environment'; | |
| import Ember from 'ember'; | |
| import DS from 'ember-data'; | |
| const { inject, computed } = Ember; | |
| export default DS.RESTAdapter.extend({ | |
| host: config.apiHost, | |
| session: inject.service('session'), | |
| headers: computed('session.authenticationToken', function() { // this part is awesome: | |
| return { | |
| 'Authorization': this.get('session.authenticationToken') ? | |
| `Token ${this.get('session.authenticationToken')}` : undefined | |
| }; | |
| }) | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment