How get token from ember-simple-auth-token to use with Websocket? - ember.js

In my implementation below I try get the token from ember-simple-auth-token and use with a URL, used to connect with ActionCable:
...
export default Route.extend({
store: service(),
currentUser: service(),
session: service(),
cable: service(),
setupConsumer: on('init', function() {
let token = this.get('session.data.authenticated.jwt');
let consumer = this.get('cable')
.createConsumer(`wss://api.${config.APP.host}/cable?token=${token}`);
let channelMixin = Mixin.create({
received(data) {
this.get('store').pushPayload(data);
}
});
consumer.subscriptions.create({
channel: 'ChatroomsChannel'
}, channelMixin);
}),
...
});
This works only at first request. I need store this in a cookie? Thanks.

The follow code solves my issue:
import Route from 'ember-route';
import service from 'ember-service/inject';
import Mixin from 'ember-metal/mixin';
import config from 'apollo-enterprise/config/environment';
export default Route.extend({
session: service(),
cable: service(),
afterModel(model) {
this.get('session.store').restore().then((data) => {
let token = data.authenticated.jwt;
let consumer = this.get('cable')
.createConsumer(`wss://api.${config.APP.host}/cable?token=${token}`);
let channelMixin = Mixin.create({
store: service(),
received(data) {
this.get('store').pushPayload(data);
}
});
consumer.subscriptions.create({
channel: 'MessagesChannel',
chatroom_id: model.id
}, channelMixin);
});
},
setupController(controller) {
this._super(...arguments);
controller.set('message', {});
},
actions: {
sendMessage(params) {
let chatroom = this.controller.get('model');
let message = this.get('store').createRecord('message', params);
message.set('chatroom', chatroom);
message.save().then(() => {
this.controller.set('message', {});
});
}
}
});

Related

Setting up admin views with Ember Simple Auth in Ember.js

I'm new to Ember.js and I'm using Ember Simple Auth and I'm having a hard time trying to figure out how to get the current user that is logged in and then checking if the user is an admin so I can display admin only thinks in templates. Currently I am using jwt authentication using Ember Simple Auth Token and a Ruby on Rails backend. Any help in pointing me in the right direction would be great.
I've currently tried getting the example on the Ember Simple Auth to work
https://github.com/simplabs/ember-simple-auth/blob/master/guides/managing-current-user.md
When the user authenticates the jwt is returning the token and the user_id. The issue is that I'm not getting the name or any details about the user when the user is logged in.
I'm trying to access the current user (Which might be wrong) by doing this
{{currentUser.user.name}}
controller/application.js
import Ember from 'ember';
const { inject: { service }, Component } = Ember;
export default Ember.Controller.extend({
session: service('session'),
currentUser: service('current-user')
});
routes/application.js
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
const { service } = Ember.inject;
export default Ember.Route.extend(ApplicationRouteMixin, {
currentUser: service(),
beforeModel() {
return this._loadCurrentUser();
},
sessionAuthenticated() {
this._super(...arguments);
this._loadCurrentUser().catch(() => this.get('session').invalidate());
},
_loadCurrentUser() {
return this.get('currentUser').load();
}
});
services/current-user.js
import Ember from 'ember';
const { inject: { service }, isEmpty, RSVP } = Ember;
export default Ember.Service.extend({
session: service('session'),
store: service(),
load() {
return new RSVP.Promise((resolve, reject) => {
let userId = this.get('session.data.authenticated.user_id');
if (!isEmpty(userId)) {
return this.get('store').find('user', userId).then((user) => {
this.set('user', user);
}, reject);
} else {
resolve();
}
});
}
});
You need to call findRecord
load() {
return new RSVP.Promise((resolve, reject) => {
let userId = this.get('session.data.authenticated.user_id');
if (!isEmpty(userId)) {
return this.get('store').findRecord('user', userId).then((user) => {
this.set('user', user);
resolve();
}, reject);
} else {
resolve();
}
});
}

Emberjs: How to redirect to the last accessed route after session invalidated

We are using ember-simple-auth with cookie authentication and we want to redirect to the last accessed route after we login again when the cookie expires. We manage to do the redirection for the following scenarios:
Not authenticated and try to access a route from url
Not authenticated and select an item from the navigation menu
Both, after successful authentication, we redirected to the requested route.
But, we want when our session cookie expired and the user tries to access a route to invalidate the session and redirect the user back to authentication page. When the user log in back we want to redirect him to the requested route. For now we store the previous transition so we can do the redirection but after we invalidate the session the data are lost.
What is the best way to do this?
Our code looks like:
Custom Authenticator
import Ember from 'ember';
import Base from 'ember-simple-auth/authenticators/base';
export default Base.extend({
restore() {
return new Ember.RSVP.Promise(function(resolve, reject) {
let sessionCookie = window.Cookies.get('beaker.session.id');
if(!window.isUndefined(sessionCookie)) {
resolve(true);
}else{
reject();
}
});
},
authenticate(data) {
return new Ember.RSVP.Promise(function (resolve, reject) {
Ember.$.ajax({
type: 'post',
url: '/core/authentication/basic/login',
data: data
}).then((response) => {
resolve({
responseText: response
});
}, (error) => {
reject(error);
});
});
},
invalidate() {
return new Ember.RSVP.Promise(function (resolve, reject) {
Ember.$.ajax({
type: 'post',
url: '/core/authentication/basic/logout'
}).then(() => {
resolve(true);
}, () => {
reject();
});
});
}
});
Application Route:
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
export default Ember.Route.extend(ApplicationRouteMixin, {
session: Ember.inject.service('session'),
beforeModel(transition) {
if(!this.get('session.isAuthenticated') && transition.targetName !== 'core.authentication') {
this.set('previousTransition', transition);
this.transitionTo('core.authentication');
}
},
actions: {
willTransition(transition) {
if (!this.get('session.isAuthenticated')) {
this.set('previousTransition', transition);
} else {
let previousTransition = this.get('previousTransition');
if (previousTransition) {
this.set('previousTransition', null);
previousTransition.retry();
}
}
}
}
});
Authentication Route
import Ember from 'ember';
export default Ember.Route.extend({
session: Ember.inject.service('session'),
actions: {
login() {
let that = this;
let { username, password } = this.controller.getProperties('username', 'password');
let data = {username: username, password: password};
if(this.get('session.isAuthenticated')) {
this.get('session').invalidate();
}
this.get('session').authenticate('authenticator:basic', data).then(() => {
let data = that.get('session.data.authenticated');
// show response message
}, (error) => {
// show error
});
}
}
});
You can add the previous transition inside the session data, like this
this.get('session').set('data.previousTransition', transition.targetName);
because that is still persisted after the session is invalidated.
And then get it back from the store, and do the transition:
this.get('session.store').restore().then(data => {
if (data.previousTransition !== null) {
this.transitionTo(data.previousTransition)
}
})
I solved it by using invalidationSucceded here.
this.get('session').on('invalidationSucceeded', () => this.transitionToRoute('dashboard'))

Ember simple auth 1.0.1 custom authenticator

I am updating my existing code done in ember-simple-auth: 0.8.0 to ember-simple-auth: 1.0.1
There are two problems
It is not persisting a session
REST Calls needed to be having withCredentials: true, not sure where I can set them.
Here is my code
//config/environment.js
ENV['ember-simple-auth'] = {
store: 'simple-auth-session-store:local-storage',
authorizer: 'authorizer:custom',
routeAfterAuthentication: '/dashboard',
routeIfAlreadyAuthenticated: '/dashboard'
};
My authenticator
//authenticators/custom.js
import Ember from 'ember';
import Base from 'ember-simple-auth/authenticators/base';
import config from '../config/environment';
export default Base.extend({
restore(data) {
return new Ember.RSVP.Promise(function (resolve, reject) {
if (!Ember.isEmpty(data.token)) {
resolve(data);
}
else {
reject();
}
});
},
authenticate(options) {
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
type: "POST",
url: config.serverURL + '/api/users/login',
data: JSON.stringify({
username: options.identification,
password: options.password
}),
contentType: 'application/json;charset=utf-8',
dataType: 'json'
}).then(function(response) {
Ember.run(function() {
resolve(response);
});
}, function(xhr) {
Ember.run(function() {
reject(xhr.responseJSON || xhr.responseText);
});
});
});
},
invalidate(data) {
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
type: "POST",
url: config.serverURL + '/api/users/logout'
}).then(function(response) {
Ember.run(function() {
resolve(response);
});
}, function(xhr) {
Ember.run(function() {
reject(xhr.responseJSON || xhr.responseText);
});
});
});
}
});
My authorizer (you can see that I am trying to update my old code)
//authorizers/custom.js
import Ember from 'ember';
import Base from 'ember-simple-auth/authorizers/base';
export default Base.extend({
authorize(sessionData, block) {
if (!Ember.isEmpty(sessionData.token)) {
block('X-CSRF-Token', sessionData.token);
block('Content-Type', 'application/json;charset=utf-8');
block('withCredentials', true);
}
}
//authorize(jqXHR, requestOptions) {
// if (!(requestOptions.data instanceof FormData)){
// requestOptions.contentType = 'application/json;charset=utf-8';
// }
//
// requestOptions.crossDomain = true;
// requestOptions.xhrFields = {
// withCredentials: true
// };
//
//
// var token = this.get('session.token');
// console.error(jqXHR);
// if (this.get('session.isAuthenticated') ) {
// jqXHR.setRequestHeader('X-CSRF-Token', token);
// }
//}
});
My application adapter
import DS from 'ember-data';
import config from '../../config/environment';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
export default DS.RESTAdapter.extend(DataAdapterMixin, {
authorizer: 'authorizer:custom',
namespace: 'api',
host: config.serverURL,
});
Dashboard
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
session: Ember.inject.service('session'),
needs: 'application',
setupController: function(controller, model){
this.controllerFor('application').set('pageTitle', 'Dashboard');
this._super(controller, model);
}
});
If I do console.log(this.get('session.isAuthenticated'); it returns me true, but when I use that in template it dont work
{{#if session.isAuthenticated}}
1
{{else}}
0
{{/if}}
On my laravel end, i can see that session is created and user is logged in, on Ember side, it was previously setting the session and then resends the credentials with each request. Now when it send another request. I think it is without credentials: True and laravel returns 401. I also tried sending a garbage header and laravel CORS refused that it is not in allowed headers.
Thank you
The authorizer config setting doesn't exist anymore in 1.0 as auto-authorization has been dropped. See the API docs for info on how to add authorization to outgoing requests:
http://ember-simple-auth.com/api/classes/SessionService.html#method_authorize
http://ember-simple-auth.com/api/classes/DataAdapterMixin.html
Also your authorizer should not call the block several times but only ones, passing all authorization data at once.
Also make sure you inject the session service into all controllers and components for templates you use the session in.

Empty model in Route

I have the following route:
import Ember from 'ember';
export default Ember.Route.extend({
ajax: Ember.inject.service(),
queryParams: {
search: {
refreshModel: true
}
},
beforeModel: function() {
var params = this.paramsFor('recipes');
var that = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
that.get('ajax').request({
url: "/recipes",
method: "GET",
data: {
namePart: params.search
}
},
function(response) {
that.store.unloadAll("recipe");
response.forEach(function(item) {
that.store.push(that.store.normalize("recipe", item));
});
resolve();
});
});
},
model: function() {
this.store.peekAll('recipe');
}
});
And controller:
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: ['search'],
search: null
});
The request is successful. And I even see appropriate data in the store. But route/controller model is null. What I'm doing wrong?
You're missing return keyword in model:
model() {
return this.store.peekAll('recipe');
}

ember-cli simple-auth custom authorization

i am trying to use ember-simple-auth with custom authentication and authorization: authenticator works but authorizer doesn't. Token successfully assigned but there is no injection in ajax calls.
app/authenticator/custom.js
import Ember from 'ember';
import Base from 'simple-auth/authenticators/base';
export default Base.extend({
tokenEndpoint: 'http://...',
restore: function(data) {
return new Ember.RSVP.Promise(function(resolve, reject) {
if (!Ember.isEmpty(data.token)) {
resolve(data);
} else {
reject();
}
});
},
authenticate: function(credentials) {
var _this = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
url: _this.tokenEndpoint,
type: 'POST',
data: JSON.stringify({ username: credentials.identification, password: credentials.password }),
contentType: 'application/json'
}).then(function(response) {
Ember.run(function() {
resolve({ token: response.token });
});
}, function(xhr, status, error) {
var response = JSON.parse(xhr.responseText);
Ember.run(function() {
reject(response.error);
});
});
});
},
invalidate: function() {
var _this = this;
return new Ember.RSVP.Promise(function(resolve) {
Ember.$.ajax({ url: _this.tokenEndpoint, type: 'DELETE' }).always(function() {
resolve();
});
});
},
});
app/authorizers/custom.js
import Ember from 'ember';
import Base from 'simple-auth/authorizers/base';
export default Base.extend({
authorize: function(jqXHR, requestOptions) {
if (this.get('session.isAuthenticated') && !Ember.isEmpty(this.get('session.secure.token'))) {
jqXHR.setRequestHeader('X-CSRFToken', this.get('session.secure.token'));
}
}
});
app/initializers/authentication.js
import CustomAuthenticator from 'app/authenticators/custom';
import CustomAuthorizer from 'app/authorizers/custom';
export default {
name: 'authentication',
before: 'simple-auth',
initialize: function(container) {
container.register('authenticator:custom', CustomAuthenticator);
container.register('authorizer:custom', CustomAuthorizer);
}
};
config/environment.js
ENV['simple-auth'] = {
authorizer: 'authorizer:custom',
crossOriginWhitelist: ['http://...']
};
app/controllers/login.js
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
authenticate: function(){
var credentials = this.getProperties('identification', 'password');
this.get('session').authenticate('authenticator:custom', credentials);
}
}
});