node.jsember.jsember-simple-auth

Managing user roles in emberjs?


I have a nodejs api as shown below

route.post("/token",function(req,res){
    authLib
        .checkForm(req.body)
        .then(authLib.findUser)
        .then(authLib.isValidUser)
        .then(authLib.authenticate)
        .then(authLib.genToken)
        .then((token)=>{
            res
                .status(200)
                .json({'access_token': token});
        })
        .catch((err)=>{
            res
                .status(400)
                .json({'error': err.message});
        });
});

The model for user contains a field with user role. Each user role has a different dashboard. I have implemented ember-simple-auth with oauth2-password-grant and the template for dashboard is as shown below

{{#if session.isAuthenticated}}
    {{#app-dashboard}}
    {{/app-dashboard}}
{{else}}
    {{#landing-app}}
    {{/landing-app}}
{{/if}}

The problem is how can i distinguish between the user roles. One method could be to use ajax requests to fetch role but that would mean an additional XHR request for all views. Also another problem with using XHR in Ember.$ is that the authorization token is not attached to request. What is the best way to solve this issue ?


Solution

  • I haven't used ember-simple-auth, but one approach that might help would be to send a role / permission object along with the token on successful user "login". Then create a 'user-permissions' Ember service that stores the role / permission object and can check if a user has a certain permission when needed. I'll use an array as an example permission object. You should be able to do this with a single XHR request.

    Of course, any client-side "security" is inherently insecure, so make sure you protect your routes from user behavior on the server-side.

    First, you'll need some roles or permissions in your database associated with users. Then add some logic to your Node API to return a list of permissions for the authenticated user along with that token.

    Then, in Ember, define a permissions service like this:

    export default Ember.Service.extend({
        permissions: [], // Sample permissions: "seeAdminPanel", "deleteUsers"
    
        // You can create a computed property to check permissions (good for templates)
        canDeleteUsers: Ember.computed('permissions', function() {
            //Check that the permissions object contains the deleteUsers permission
            let permissions = this.get('permissions');
            let permissionToCheck = 'deleteUsers';
            let userHasPermission = permissions.indexOf(permissionToCheck) > -1; 
            return (userHasPermission);
        }),
    
        // Or create a generic function to check any permission (good for checking in a function)
        canCurrentUser(permissionToCheck) {
            let permissions = this.get('permissions');
            return (permissions.indexOf(permissionToCheck) > -1);
        }
    });
    

    When your Ember app hits your Node api it will get the permissions object in a successful response. Set the object on the permissions service like so in your success callback (remember to inject your service):

    let userPermissionsService = this.get('userPermissionsService');
    userPermissionsService.set('permissions', ["deleteUsers"]);
    

    Then use in a template:

    {{#if userPermissionsService.canDeleteUsers}}
        <button>Delete User</button>
    {{/if}}
    

    Or use in a function:

    let userPermissionsService = this.get('userPermissionsService');
    if (userPermissionsService.canCurrentUser("deleteUsers")) {
        this.deleteUser()
    }
    

    In terms of passing the authorization token back with an XHR request, you should be able to do it manually by using a regular jquery ajax request (setting the headers object in the request as per http://api.jquery.com/jQuery.ajax/) or if you want to attach it to every Ember data request, customizing the REST adapter should work: https://guides.emberjs.com/v2.13.0/models/customizing-adapters/#toc_headers-customization