Trouble transitioning to current user after signing in with Emberfire - ember.js

I am using Emberfire for my authentication and database and I am able to sign in, but it does not redirect me to my current users page after that. It also throws an error at me saying that no user exists at the custom url but my firebase console shows the user with the correct id that I am redirecting to.
Here is my login controller:
import Ember from 'ember';
export default Ember.Route.extend({
beforeModel: function() {
return this.get('session').fetch().catch(function() {});
},
actions: {
signIn: function() {
var controller = this.get('controller');
var email = controller.get('email');
var password = controller.get('password');
this.get('session').open('firebase', { provider: 'password', 'email': email, 'password': password}).then(function(data) {
console.log(data.currentUser);
});
let uid = this.get('session').get('uid');
this.store.findRecord('user', uid).then(user => {
console.log(user.get('firstName'));
this.transitionTo('user', uid);
});
},
signOut: function() {
this.get('session').close();
}
}
});
Here is my router:
Router.map(function() {
this.route('signup');
this.route('home', { path: '/' });
this.route('login');
this.route('user', { path: '/user/:user_id' });
});

You have to wait for the authentication to finish. That's what the .then is for. In your current code, you're getting the uid from the session before it's finished authenticating.
This should work:
import Ember from 'ember';
export default Ember.Route.extend({
beforeModel: function() {
return this.get('session').fetch().catch(function() {});
},
actions: {
signIn: function() {
var controller = this.get('controller');
var email = controller.get('email');
var password = controller.get('password');
var self = this;
this.get('session').open('firebase', { provider: 'password', 'email': email, 'password': password}).then(function(data) {
console.log(data.currentUser);
let uid = this.get('session').get('uid');
this.store.findRecord('user', uid).then(user => {
console.log(user.get('firstName'));
self.transitionTo('user', uid);
});
});
},
signOut: function() {
this.get('session').close();
}
}
});

Related

Set multiple data with Ember and make it persist on Firebase

I am trying to set data from two models (that has hasMany & belongsTo relationship) and save them to firebase.
'list' data ends up being saved to firebase but not user data.
I think I'm doing something wrong at step 3. I'd appreciate your help!
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('list');
},
actions: {
createList: function() {
var newListTitle = this.controllerFor('lists').get('newListTitle');
var username = this.get('session.user.displayName');
alert(this.get('session.user.displayName'));
if (Ember.isBlank(newListTitle)) { return false; }
//1
var list = this.store.createRecord('list', {
title: newListTitle,
user: username,
});
//2
this.controllerFor('lists').set('newListTitle', '');
var _this = this;
//3
list.save().then(function(list) {
user.get('lists').addObject(list);
user.save();
_this.transitionTo('lists.show', list); //4
});
}
}
});
Restructured your adding logic as well as user defined models, also modified your route, which could look like this in Edit and View mode. Meaning you can have more than one item returned from "model".
// Update models
App.List = DS.Model.extend({
value: DS.attr('string')
});
App.User = DS.Model.extend({
name: DS.attr('string')
});
App.UserLists = DS.Model.extend({
user: DS.belongsTo('user'),
list: DS.belongsTo('list')
});
export default Ember.Route.extend({
LIST:SHOW ROUTE
model: function(params) {
var store = this.get('store');
var userPromise = store.find('user', params.id);
return Ember.RSVP.hash({
user: userPromise,
userList : userPromise.then(function(user) {
return store.find(userList, { WhereUserIdIs : user.get('id') })
});
});
},
actions: {
createList: function() {
var self = this;
var failure = function(reason) {
// handle stuff
};
var list = this.store.createRecord('list', {
title: this.get('title'),
});
var user = this.get('user');
var usersList = store.createRecord('userList', {
'user': user,
'list': list
});
list.save().then(function(list) {
user.save().then(function() {
userList.save().then(function() {
self.transitionTo('lists.show', list.get('id'));
}, failure);
}, failure);
}, failure);
}
});

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

Uncaught TypeError: Cannot read property 'login' of undefined

I'm trying to set up OAuth with Firebase and Ember. For some reason it's returning the error
Uncaught TypeError: Cannot read property 'login' of undefined
App.LoginController = Ember.ObjectController.extend({
actions: {
login: function() {
var controller = this;
debugger;
controller.get("session").login().then(function(user) {
// Persist your users details.
}, function() {
// User rejected authentication request
});
}
},
});
I was thinking maybe the user is undefined, but I've defined it in a model:
App.User = DS.Model.extend({
username: DS.attr('string'),
});
Then I thought maybe it's the "session" that's undefined--I used the debugger to look up & it says it's an unknown mixin.
var session = Ember.Object.extend({
ref: new Firebase("https://glowing-fire.firebaseio.com/"),
addFirebaseCallback: function() {
var session = this;
this.get("ref").onAuth(function(authData) {
if (authData) {
session.set("isAuthenticated", true);
} else {
session.set("isAuthenticated", false);
}
});
}.on("init"),
login: function() {
return new Promise(function(resolve, reject) {
this.get("ref").authWithOAuthPopup("facebook", function(error, user) {
if (user) {
resolve(user);
} else {
reject(error);
}
});
});
},
currentUser: function() {
return this.get("ref").getAuth();
}.property("isAuthenticated")
});
App.Session = Ember.Object.extend({
initialize: function(container, app) {
app.register("session:main", session);
app.inject("controller", "session", "session:main");
app.inject("route", "session", "session:main");
}
});
I'd really appreciate your help!
The issue might be that you are trying to access an injected property, but the code that does the injection is never called. The recommended way to inject properties is described on this page.
More specifically the samples below (from the Ember.js website) should help
Using an application initializer:
App = Ember.Application.extend();
App.Logger = Ember.Object.extend({
log: function(m) {
console.log(m);
}
});
App.IndexRoute = Ember.Route.extend({
activate: function(){
// The logger property is injected into all routes
this.logger.log('Entered the index route!');
}
});
Ember.Application.initializer({
name: 'logger',
initialize: function(container, application) {
application.register('logger:main', App.Logger);
application.inject('route', 'logger', 'logger:main');
}
});
App.create();
or directly on the application:
App = Ember.Application.create();
App.register('logger:main', {
log: function(m) {
console.log(m);
}
}, { instantiate: false });
App.inject('route', 'logger', 'logger:main');

Ember-simple-auth with laravel

I'm having trouble creating a custom authenticator for my laravel backend. I'm not sure if this is the correct custom authenticator for laravel, but I'm using this as a starting point (https://github.com/simplabs/ember-simple-auth/blob/master/examples/6-custom-server.html).
My Ember.SimpleAuth is undefined. Here is what I have in my app.js.
import Ember from 'ember';
import Resolver from 'ember/resolver';
import loadInitializers from 'ember/load-initializers';
Ember.MODEL_FACTORY_INJECTIONS = true;
window.ENV = window.ENV || {};
window.ENV['simple-auth'] = {
authorizer: 'authorizer:custom'
};
Ember.Application.initializer({
name: 'authentication',
before: 'simple-auth',
initialize: function(container, application) {
//register the laravel authenticator so the session can find it
container.register('authenticator:laravel', App.LaravelAuthenticator);
container.register('authorizer:custom', App.CustomAuthorizer);
}
});
var App = Ember.Application.extend({
modulePrefix: 'ember-simple-auth-sample', // TODO: loaded via config
Resolver: Resolver
});
App.LaravelAuthenticator = Ember.SimpleAuth.Authenticators.Base.extend({
tokenEndpoint: '/v4/session',
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({ session: { identification: credentials.identification, password: credentials.password } }),
contentType: 'application/json'
}).then(function(response) {
Ember.run(function() {
resolve({ token: response.session.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();
});
});
}
});
// the custom authorizer that authorizes requests against the custom server
App.CustomAuthorizer = Ember.SimpleAuth.Authorizers.Base.extend({
authorize: function(jqXHR, requestOptions) {
if (this.get('session.isAuthenticated') && !Ember.isEmpty(this.get('session.token'))) {
jqXHR.setRequestHeader('Authorization', 'Token: ' + this.get('session.token'));
}
}
});
loadInitializers(App, 'ember-simple-auth-sample');
export default App;
Ember.SimpleAuth doesn't exist anymore, it now has it's own global SimpleAuth when you use the browserified distribution. It looks like you're using ember-cli though which means you're using the AMD distribution of Ember Simple Auth anyway which doesn't define any global at all. For instructions on how to use Ember Simple Auth with ember-cli see this blog post.
Apart from that your authenticator and authorizer look fine on first glance and should generally work that way.

How to store the user in a session

I am trying to set up ember-simple-auth with a django-rest-framework backend, but I'm running into some trouble saving the user to the session. I have to be able to do something like this in my templates:
<h2>Welcome back, {{session.user}}</h2>
So following several guides I found, I have got the authentication and authorization working so that I can get a valid token and use is in requests. To get the user on the session, I have modified App.CustomAuthenticator.authenticate so that when the token is returned, the username is also stored to the session:
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,
username: credentials.identification
});
});
}, function(xhr, status, error) {
var response = JSON.parse(xhr.responseText);
Ember.run(function() {
reject(response.error);
});
});
});
},
I then modified Application.intializer to give session a user property:
Ember.Application.initializer({
name: 'authentication',
before: 'simple-auth',
initialize: function(container, application) {
// register the custom authenticator and authorizer so Ember Simple Auth can find them
container.register('authenticator:custom', App.CustomAuthenticator);
container.register('authorizer:custom', App.CustomAuthorizer);
SimpleAuth.Session.reopen({
user: function() {
var username = this.get('username');
if (!Ember.isEmpty(username)) {
return container.lookup('store:main').find('user', {username: username});
}
}.property('username')
});
}
});
However, when {{session.user.username}} is rendered it is just an empty string. My questions are:
Is this really the best way to assigning a user to the session? It seems clumsy to me but I can't see anything better.
I assume that the empty string is because a Promise is returned rather than a User object, so how to I resolve it?
To tag off of #marcoow's response, here's how to implement it in Ember CLI:
index.html:
window.ENV['simple-auth'] = {
authorizer: 'simple-auth-authorizer:devise',
session: 'session:withCurrentUser'
};
initializers/customize-session.js:
import Session from 'simple-auth/session';
var SessionWithCurrentUser = Session.extend({
currentUser: function() {
var userId = this.get('user_id');
if (!Ember.isEmpty(userId)) {
return this.container.lookup('store:main').find('user', userId);
}
}.property('user_id')
});
export default {
name: 'customize-session',
initialize: function(container) {
container.register('session:withCurrentUser', SessionWithCurrentUser);
}
};
With the 0.6.4 release you can now specify a custom session class without having to reopen, see release note here: https://github.com/simplabs/ember-simple-auth/releases/tag/0.6.4. This is how it works:
App.CustomSession = SimpleAuth.Session.extend({
account: function() {
var accountId = this.get('account_id');
if (!Ember.isEmpty(accountId)) {
return this.container.lookup('store:main').find('account', accountId);
}
}.property('account_id')
});
…
container.register('session:custom', App.CustomSession);
…
window.ENV['simple-auth'] = {
session: 'session:custom',
}