User's role and how to restrict access to routes (kind of ACL)


#1

Hello everybody!

I’m new to Ember and I have a problem I can’t solve in a clean and easy way: restrict access to different routes according the current user’s role.

I’m planning an app where the users have to login in order to access the app. Each user is assigned a role (Admin, Secretary, Applicant,…) and only the administrators can access some routes, applicants can access other, etc.

The identification and session stuff is solved with Ember Simple Auth but I don’t know which approach is better to manage the access control.

Any ideas?

Thank you in advance and sorry my english.


#2

We do something like this:

App.AuthenticatedRoute = Ember.Route.extend
  beforeModel: (transition) ->
    ability = @get('ability')
    return if Ember.isEmpty(ability)

    console.log "Checking for required ability: #{ability}"

    if @get('currentUser.isLoaded')
      @check(ability)
    else
      deferred = Ember.Deferred.create()
      @get('currentUser.model').one 'didLoad', =>
        deferred.resolve()
        @check(ability)
      return deferred

  check: (ability) ->
    return if @get("currentUser.#{ability}")
    console.log "Current user does not have ability: '#{ability}'"
    @transitionTo 'unauthorized'

CurrentUser is a controller which exposes computed properties like:

canEatCake: function(){
  return @get('role') == 'partyplanner'     
}.property('user.role')

Our route subclass from AuthenicatedRoute and add a field called ability (which we check). There are lot of improvements you could make the above code, for example instead of Ember.Deferred you could use a RSVP promise and make the code much simpler etc…

I hope this helps you get started.


#3

I think I understand your proposal and it’s a good start.

By the way, you have given me an idea. I think that it can be managed at route’s level. For example: you can define a route’s property where you specify the roles that can access that route. This way, you only have to check if the user’s rol is in the list:

App.PostsAddRoute = Ember.Route.extend({
    access: [ 'Admin', 'RegisteredUser' ],
    beforeModel: function(transition) {
        if (this.get('access').contains(this.get('currentUser.role'))) {
            return true;
        }
        // manage the unauthorized attempt
        this.transitionTo('unauthorized'); // or whatever
    }
});

Sorry my poor code but as I said I’m new to Ember and I don’t have much experience.

I think this approach has a con: when you create a new role you have to revisit every route in which it’s allowed and modify the access property:

...
access: [ 'Admin', 'RegisteredUser', 'NewRole' ],
...

I don’t know if it’s a good idea so I’d appreciate your comments.

Thanks!


#4

That’s exactly what we do. We call it ability, but abilities map to roles. We have some additional weirdness in that we can have our user model loaded asynchronously. But you’re definitely on the right track!