I'm creating a frontend for a C program with an embedded web interface that has a simple REST api. I'd like to use ember-simple-auth with a customer authenticator and authorizer that talks to that api endpoint.
var Authenticator = AuthenticatorBase.extend({
restore: function(data) {
...
},
authenticate: function(credentials) {
var _this = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
... ??? ...
});
},
invalidate: function() {
var _this = this;
return new Ember.RSVP.Promise(function(resolve) {
... ??? ...
});
},
});
In the ember-simple-auth examples, I see the custom authenticator implementation that uses Ember.$.ajax to post to server like this:
authenticate: function(credentials) {
var _this = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
url: _this.tokenEndpoint,
type: 'POST',
data: { username: credentials.identification,
password: credentials.password },
}).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);
});
});
});
},
But I'd rather use ember-data for this (I think) -- new to ember and ember-data, so it's not clear. Assuming my API endpoint is /session, what would my authenticate method look like with ember-data?
On a related note: I'm using ember-cli and running ember server for development. How do I tell ember-data to point to my C-based server for the REST calls? I'm trying this, but doesn't seem to be affecting the ember-data calls - they just go to the ember server:
// app/adapters/application.js
import DS from "ember-data";
export default DS.RESTAdapter.extend({
host: 'localhost:48880',
namespace: '/'
});
When you want to use Ember Data you'd need to have a Session model or so so that when you create an instance of that a POST to /sessions would be triggered. I don't actually think that makes sense though and you don't really get any benefits from using Ember Data in that case - I'd recommend to simply go with plain Ember.$.ajax and use Ember Data for your actual model data.
Related
My authenticators/custom.js:
import Ember from 'ember';
import Base from 'simple-auth/authenticators/base';
export default Base.extend({
restore: function(data) {
},
authenticate: function(email, password, authenticateCallback) {
return new Ember.RSVP.Promise((resolve, reject) => {
Ember.$.ajax({
type: 'POST',
url: apiOrigin + '/api/v1/login',
data: {
email: email,
password: password
},
dataType: 'json'
}).then(function(userData){
console.log('login post success', userData)
authenticateCallback(userData)
Ember.run(function() {
resolve(userData.uuid)
})
})['catch'](function(main){
alert('login error ' + JSON.stringify(main))
console.error('\'caught\' error from login post request', arguments);
})
})
},
invalidate: function(data) {
}
});
And login/controller.js:
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service('session'),
application: Ember.inject.controller(),
actions: {
authenticate() {
let { identification, password } = this.getProperties('identification', 'password');
this.get('session').authenticate('authenticator:custom', identification, password, (userData) => {
//TODO set these properties on ember-simple-auth's session object instead of application controller
this.get('application').setProperties(userData)
this.transitionToRoute('associate-device')
}).catch((reason) => {
this.set('errorMessage', reason.error);
})
}
}
});
My associate-device route is an AuthenticatedRoute.. I don't get an error, but instead, the last thing printed to the console is "Preparing to transition from 'login' to 'associate-device'"
Basically, ember simple auth documents here http://ember-simple-auth.com/api/classes/BaseAuthenticator.html#method_authenticate that "A resolving promise will result in the session becoming authenticated. Any data the promise resolves with will be saved in and accessible via the session service's data.authenticated property (see data). A rejecting promise indicates that authentication failed and will result in the session remaining unauthenticated."
However, my session does not seem to be authenticated after I successfully resolve my promise.
$.ajax has no catch method. This exception was hidden because I was copy-pasting away from the documentation for writing custom authenticators. To expose any exceptions occurring in your custom authenticators authenticate method, you should probably console.log them like so:
// app/controllers/login.js
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service('session'),
actions: {
authenticate() {
let { identification, password } = this.getProperties('identification', 'password');
this.get('session').authenticate('authenticator:oauth2', identification, password).catch((reason) => {
// **CHANGE THE BELOW LINE**
console.error('exception in your authenticators authenticate method', reason)
});
}
}
});
Setup:
Ember : 2.0.2
Ember Data : 2.0.1
jQuery : 1.11.3
Ember Simple Auth : 1.0.0 (jjAbrams Branch)
Ember CLI : 1.13.8
I'm using pretender to mock a server.
Usecase:
Using a custom authenticator to interface with the server.
Have 2 routes: login, protected (and by default index,application)
When I login with the right credentials, the authenticate method of the authenticator gets called and successfully logs the response object which is passed to resolve().
Observations:
After logging in and being directed to the protected page, Refreshing the protected route (Which has AuthenticatedRouteMixin) leads back to login page.
Localstorage has no values bound to it even after successful login.
Before login: ember_simple_auth:session -> {"authenticated":{}}
restore() method of authenticator never called.
Going to another route from the protected route after auth and coming back goest to login page again.
//authenticators/custom.js
import Ember from 'ember';
import Base from 'ember-simple-auth/authenticators/base';
export default Base.extend({
restore: function (data) {
return new Ember.RSVP.Promise(function (resolve, reject) {
console.log("RESOLVE",data);
if (!Ember.isEmpty(data.token)) {
//TODO Remove log
resolve(data);
} else {
console.log("REJECTING",data);
reject();
}
});
},
authenticate(credentials) {
return new Ember.RSVP.Promise((resolve, reject) =>
Ember.$.ajax({
url: '/token',
type: 'POST',
data: JSON.stringify({
email: credentials.identification,
password: credentials.password
}),
contentType: 'application/json;charset=utf-8',
dataType: 'json'
}).then(function (response) {
Ember.run(function () {
//This logs the expected information
console.log("Response", response, response.token, response.user);
resolve(response);
});
}, function (xhr, status, error) {
console.log("error", error, xhr.responseText);
var response = xhr.responseText;
Ember.run(function () {
reject(response);
});
}));
},
invalidate(token) {
return API.logout(token);
}
});
//environment.js
ENV['ember-simple-auth'] = {
store: 'session-store:local-storage',
routeAfterAuthentication: '/protected'
};
TLDR;
How do I make the session persist?
I got it all working together finally. Ember 2.0 and ESA 1.0
Here are the steps I took:
Create a new ember cli project
Update Ember and ember data values to ^2.0.0 in bower.json Source
Add ESA jjAbrams dep to package.json Source
run npm install && bower install
Gotchas: (This was the original problem which caused the problems described in the question)
If you're upgrading from older versions of ESA, all references to 'simple-auth/..' should be updated to refer 'ember-simple-auth/..' instead..
.. This include imports for authenticators, authorizers, stores, mixins and the Config key in the config/environment.js file.
All this shouldn't be an issue once ESA 1.0 and Ember Cli for Ember 2.0 comes out :)
currently I'm changing my project from ember to ember-cli and run in a issue I can't get rid of. I am really not sure where the problem is, since I also updated ember and ember-data.
I get the Error:
Uncaught Error: Cannot re-register: `store:main`, as it has already been resolved.
I'm trying to load a user via the simple-auth Session.
import UserSession from '../session/user';
export default {
name: 'user-session',
before: 'simple-auth',
after: 'store',
initialize: function(container, application) {
container.register('session:user', UserSession);
}
};
and the session:
import Session from 'simple-auth/session';
export default Session.extend({
setup: function(authenticator, content, trigger) {
// Do not let setup trigger
this._super.call(this, authenticator, content, false);
// Lookup user and trigger events ourselves
var store = this.container.lookup('store:main');
console.log(store.find);
var self = this;
store.find('user', content.userId)
.then(function(user) {
self.set('user', user);
self.trigger('sessionAuthenticationSucceeded');
}, function() {
console.log('ERROR: Could not resolve user of session!');
});
}
});
the store.find is there but then the error breaks it.
I also tired to inject the store like this:
Ember-Simple-Auth currentUser example help required but had the same result.
Further I tried to make it via the instance-initalizer for ember-data beta.19.
I do stuff like this:
Session from '../session/user';
export default {
name: 'user-session1',
after: 'ember-data',
initialize: function(container, application) {
var store = container.lookup('store:main');
}
};
but this ends up in:
Uncaught TypeError: container.lookup is not a function
Using:
DEBUG: -------------------------------
ember.debug.js:4874DEBUG: Ember : 1.12.1
ember.debug.js:4874DEBUG: Ember Data : 1.0.0-beta.19.2
ember.debug.js:4874DEBUG: jQuery : 1.11.3
ember.debug.js:4874DEBUG: Ember Simple Auth : 0.8.0
ember.debug.js:4874DEBUG: -------------------------------
Thx for the help
------------------ EDIT --------------------------------------------
I updated my instance-initializers based on #Artych comment where I get the store.
I removed the custom session from simple-auth and tried it with reopening
ENV['simple-auth'] = {
//session: 'session:user', ...
My function:
initialize: function(application) {
var store = application.container.lookup('store:main');
Session.reopen({
setCurrentUser: function() {
console.log('never get here');
var accessToken = this.get('access_token');
var self = this;
if (!Ember.isEmpty(accessToken)) {
//never gets here, doesn't matter if I take other variables
}
}.observes('access_token', 'id', 'userId', 'user_id')
});
}
the problem now is that it never goes into "setCurrentUser". I still can logout and in. my autenticator:
authenticate: function(credentials) {
return new Ember.RSVP.Promise(function(resolve, reject) {
var ttl = 30*60*1000; // Request login for 30 minutes
var data = _.extend(credentials, {ttl: ttl});
Ember.$.ajax({
type: 'POST',
url: ENV.api + '/users/login',
data: data,
dataType: 'json'
})
.then(function(response) {
console.log(response);
Ember.run(null, resolve, response);
}, function(xhr, status, error) {
Ember.run(null, reject, error);
});
});
},
returns:
Object {id: "xI3sPSsgdOiHLd8DcFyuOE42KhbuO8gi8BjWBJRrgHgeCESWoma99C2RtvC6tnxG", ttl: 1800000, created: "2015-07-02T14:00:06.600Z", userId: 1}
As you can see, I added a bunch of observed variables: observes('access_token', 'id', 'userId', 'user_id') which I saw in different other questions but nothings helps.
Any idea on this?
Thx
I Solved it.
Simple don't use Ember Data 1.0.0-beta.19.2. I upgraded to 1.13.4 and I was able to get the store like before.
When writing a custom authenticator using Ember.SimpleAuth with Ember-CLI, what exactly does the authenticate method of the custom authenticator need to return in order to establish a user as logged in? Below is the authenticator as it currently exists. We are using a phalcon rest api for the back end, so ultimately it seems that this method will need to hit that URL and authenticate the user on the server side, but what should the server return in order for ember.simpleauth to do what it needs to do?
import Ember from "ember";
import App from '../app';
import Base from "simple-auth/authenticators/base";
export default Base.extend({
tokenEndpoint: 'login',
restore: function(data) {
console.log('ran resotre');
},
authenticate: function(credentials) {
alert(credentials.identification);
alert(credentials.password);
},
invalidate: function() {
console.log('ran invalidate');
}
});
I would read Ember Simple Auth - API
authenticate needs to return a promise. Within the method, that promise needs to be resolved or rejected. A resolved promise would signal a successful authentication, while a rejected promise a failure in authentication. Here is how I structured a quick authenticate function.
authenticate: function (credentials, options) {
return new Ember.RSVP.Promise(function (resolve, reject) {
var loginPromise = Ember.$.post(<token url goes here>, {
username: credentials.identification,
password: credentials.password
});
loginPromise.then(function (data) {
resolve({
token: data.token,
userData: data.user
});
}, function (error) {
reject(error);
});
});
}
I am looking for a guide that will help me understand syncing models in ember. I tried to use the RestAdapter on the latest build and I am getting an error. So I decided to use the BasicAdapter based on stabilizing ember data on the ember js site.
Here is my model:
App.Accounts = DS.Model.extend({
name:DS.attr('string')
,date:DS.attr('date')
})
Here is where I declare the sync functions for the model.
App.Accounts.sync = {
list: function() {
$.ajax({
type: 'POST',
cache: false,
url: contextPath + 'account/list',
success: function(data) {
this.load()
},
error: function(jqXHR, textStatus, errorThrown) {
},
async: false
});
}
}
I am calling the list function in a setup controller:
App.TestRoute = Ember.Route.extend({
setupController:function(){
App.Accounts.list()
}
})
The function does not execute. What is the correct way to call sync functions in an ember application? Also, I could use a blog/article on this topic.
Thanks!
Have you checked out Ember Model it gives you a basic adapter without having to use EmberData.
Erik has a tutorial at embercasts.com you may need to signup to be beta user.
var attr = Ember.attr;
App.User = Ember.Model.extend({
id: attr(),
name: attr()
});
App.User.url = "/users";
App.User.adapter = Ember.RESTAdapter.create();
var newUser = App.User.create({name: "Erik"});
newUser.save(); // POST to /users.json
var existingUser = App.User.find(1); // GET /users/1.json
existingUser.set('name', 'Kris');
existingUser.get('isDirty'); // => true
existingUser.save(); // PUT /users/1.json
Cheers