Ember-simple-auth: Using ember-data REST Adapter for custom authenticator

Created on 15 Feb 2015  路  9Comments  路  Source: simplabs/ember-simple-auth

Hey,

I would like to know, if it is possible, to use ember-data REST Adapter (or other DS.Store things) for a custom authenticator.

I think it is not possible atm, because the order of the initializers does not allow it, but i would like to show some advantages, it mit bring with it, to be able to use the ember-data store:

Current-Code:

// app/authenticators/custom.js
import Base from 'simple-auth/authenticators/base';
import Ember from 'ember';

export default Base.extend({
    restore: function (data) {
        return new Ember.RSVP.Promise(function(resolve, reject) {
            if(Ember.isEmpty(data)) {
                reject();
            }
            Ember.$.getJSON('/api/sessions').then(function(responseObject) {
                if(responseObject.sessions.length === 0) {
                    reject();
                    return;
                }

                if(responseObject.sessions[0].id !== data.id) {
                    reject();
                    return;
                }

                resolve(responseObject.sessions[0]);
            }, function(jqXHR) {
                reject(jqXHR);
            });
        });
    },
    authenticate: function (options) {
        return new Ember.RSVP.Promise(function(resolve, reject) {
            Ember.$.ajax({
                url: '/api/sessions',
                type: 'POST',
                data: {
                    session: options
                },
                dataType: 'json'
            }).then(function(responseObject/*, statusText, jqXHR*/) {
                Ember.run(function() {
                    resolve(responseObject.sessions[0]);
                });
            }, function(jqXHR/*, textStatus, errorThrown*/) {
                Ember.run(function() {
                    reject(jqXHR);
                });
            });
        });
    },
    invalidate: function (data) {
        console.log('invalidate', data);
    }
});

Possible improvements with a store (just kind of Pseudo Code because it does not work atm):

import Base from 'simple-auth/authenticators/base';
import Ember from 'ember';

export default Base.extend({
    restore: function (data) {
        var _this = this;
        return new Ember.RSVP.Promise(function(resolve, reject) {
            if(Ember.isEmpty(data)) {
                reject();
            }

            _this.get('store').find('session', data.id).then(function() {
                        resolve();
            }, function() {
                        reject();
            });

        });
    },
    authenticate: function (options) {
        var session = this.get('store').createRecord('session', options);
        session.save().then(function() {
                        resolve();
            }, function() {
                        reject();
            });
    },
    invalidate: function (data) {
        // same with delete record
    }
});

It is not just the simple usage of the store, but also the real "model behaviour", which would be interesting. So you could do something like:

App.Session = DS.Model.extend({
  created: DS.attr('date'),
  modified:  DS.attr('date'),
  user: DS.belongsTo('user'),
  roles: DS.hasMany('role')
});

And it is all resolved in the session to perform RBAC or something similar.

Conclusion:

  • It would be more easy to create/update/delete a session following the jsonapi.org recommendations in the REST part
  • It would be possible to have a "real" model resolved
  • It would be possible to have belongsTo and hasMany relationships in the session
  • It would be possible to check for permissions, something like:
// ...
if(this.get('session').isGranted('MYROLE'))
// ...

What do you think? Is it worth it?
Perhaps in an BaseDataAuthenticator which requires ember-data...?

invalid

Most helpful comment

I was trying to do this same thing, and I found this from http://emberjs.com/blog/2015/03/23/ember-data-1-0-beta-16-released.html

The store has now been registered as a service. So when you are using Ember Data 1.0.0-beta.16 with > Ember 1.10+ you can now inject the store into any Ember object managed by the container.

Instead of using an initializer, my custom authenticator looks like

export default Base.extend({
    store: Ember.inject.service(),

All 9 comments

You can always implement a custom authenticator that works as you describe above. Not sure what you suggest to change in Ember Simple Auth here.

The store is not accessible / undefined, when I try to use it in CustomAuthenticator:

// app/authenticators/custom.js
import Base from 'simple-auth/authenticators/base';
import Ember from 'ember';

export default Base.extend({
    restore: function (data) {
         // ...
         // undefined
         console.log(this.get('store'));
         // ...
    },
    authenticate: function (options) {
         // ...
         // undefined
         console.log(this.get('store'));
         // ... 
    },
    invalidate: function (data) {
         // ...
         // undefined
         console.log(this.get('store'));
         // ... 
    }
});

In a controller for example i could use it like:

var user = this.get('store').createRecord('user', { username: 'sandreas'});

You have to inject the store into your authenticator in an initializer.

I'm sorry, but could you provide an example for this? I did not manage to get the store in here:

// app/initializers/initializer-authentication.js
import CustomAuthenticator from '../authenticators/custom';
import CustomAuthorizer from '../authorizers/custom';

export default {
    name:       'authentication',
    before:     'simple-auth',
    initialize: function(container, application) {
        container.register('simple-auth-authenticator:custom', CustomAuthenticator);
        container.register('simple-auth-authorizer:custom', CustomAuthorizer);
        // undefined
        console.log("store", application.get('store'));
    }
};
// app/initializers/initializer-store-for-auth.js
export default {
    name:       'store-for-auth',
    after:     'store',
    initialize: function(container, application) {
        console.log("store", application.get('store:main'));
    }
};
// app/initializers/initializer-authentication.js
import CustomAuthenticator from '../authenticators/custom';
import CustomAuthorizer from '../authorizers/custom';

export default {
    name:       'authentication',
    before:     'simple-auth',
    after:       'store',
    initialize: function(container, application) {
        var store = container.lookup('store:main');
        var authenticator = CustomAuthenticator.create({ store: store });
        container.register('simple-auth-authenticator:custom', authenticator, { instantiate: false });
        container.register('simple-auth-authorizer:custom', CustomAuthorizer);
    }
};

Hey Marco,

thank you very much. You are indeed providing premium support! ;) After some research i found a slightly more elegant looking solution based on your sample. Works for me. Just wanted to provide it for others:

// app/initializers/initializer-authentication.js
import CustomAuthenticator from '../authenticators/custom';
import CustomAuthorizer from '../authorizers/custom';

export default {
    name: 'authentication',
    before: 'simple-auth',
    after: 'store',
    initialize: function (container, application) {
        container.register('simple-auth-authenticator:custom', CustomAuthenticator);
        container.register('simple-auth-authorizer:custom', CustomAuthorizer);
        application.inject('simple-auth-authenticator:custom', 'store', 'store:main');
    }
};

@sandreas: you're right - that's better

I was trying to do this same thing, and I found this from http://emberjs.com/blog/2015/03/23/ember-data-1-0-beta-16-released.html

The store has now been registered as a service. So when you are using Ember Data 1.0.0-beta.16 with > Ember 1.10+ you can now inject the store into any Ember object managed by the container.

Instead of using an initializer, my custom authenticator looks like

export default Base.extend({
    store: Ember.inject.service(),

@kielni Thank you so much for adding this here! Helped me a lot.

Was this page helpful?
0 / 5 - 0 ratings