hrdwdmrbl
hrdwdmrbl

Reputation: 5319

Declarative Authorization (permissions) for Backbone Views

Preface: Anyone coming from the Rails community is probably familiar with cancan on the server side for declaring authorization of model actions. IE. can?(:read, Project)

Background: But, in the UI layer on the frontend, I have not found anything that provides the same type of abstraction for handling what users see and what they have permission to do (obviously always have a backend auth layer as well). For example, do you show a button to the user? Do we include a 'contenteditable' element attribute? If a user clicks 'like', do we attempt to register that or do we present them with a login dialogue box?

Question: Does anyone know of a framework/tool/library/best-practice for handling this type of UI issue?

Followup: Does the question get evaluated in the view or in the template? Is this a feature of the template language or a set of boolean variables that we pass in to the template?

Aside: I had an idea for a cancan imitation tool where the method signature would be something like App.can('like',project,user), where project and user are BB model objects. The issue though might be the number of different actions a user might be able to perform on any given object. IE. like the project, edit the project, comment on the project, invite a friend to the project, etc. Some of these can be reduced to RESTful actions, but I think most would agree the UI presents more types of actions.

Upvotes: 3

Views: 1080

Answers (2)

Moustafa Samir
Moustafa Samir

Reputation: 2268

We had the same situation in our project where everything in the page should be shown and hidden according to a permissions given to the user and here is the solution I came up with.

You need to save permissions first in the user and load them in client side; then you can check them as follows

1-Declare the "filterByPermission" function in your base view (all your views should inherit this one)

class SampleProject.Views.BaseView extends Backbone.View

  filterByPermission:=>
    #these views will be removed incase user does not have a specific permission
    if @views_permissions?
      for permission, selector of @views_permissions
        unless SampleProject.current_user.has_permission permission
          @$(selector).remove()

    #these views will be removed incase user has a specific permission
    if @remove_views_permissions?
      for permission, selector of @remove_views_permissions
        if SampleProject.current_user.has_permission permission
          @$(selector).remove()

2-and then you can come in another view that inherit the base view and define your permissions in the "views_permissions" has (something similar to the events hash)

class SampleProject.Views.UsersIndex extends SampleProject.Views.BaseView
  views_permissions:
    "create_users":  "#js_create_user_li, #new_user_modal"
    "import_users": "#js_import_btn_li, #import_form_li"
    "edit_users"  :  "#edit_user_modal"
    "delete_users"  :  "#js_delete_user_li, .js-user-selector-header"

  render:=>
    #render your view here
    @filterByPermission()

3-call @filterByPermission() after rendering your view.

This way you'll have one place to control views according to permissions without adding if statements all over your code

Upvotes: 2

Dennis Rongo
Dennis Rongo

Reputation: 4611

Not sure exactly what frameworks are out there, but you can have Rails or whatever server-side framework you use render your permissions as JavaScript objects.

For instance:

var userAuth = { userId: 1234, userType: 'Admin',
                 /** A little more complex permission scenario */
                 privileges: [{ProjectA: 'admin'}, 
                              {ProjectB: 'user'}, 
                              {ProjectC: 'noaccess'}]};

So in your view or template, you can declaratively render a piece of UI element based on the permission of the user currently logged in. Using Underscore template for example, you can perform some JavaScript logic and checks.

/** Operate using a declared variable */
<% if (userAuth.userType === 'Admin') {%>
    <div>This is only shown to admin.</div>
<% } %>

/** OR operate on the actual property on the working model */
<% if (myModelProperty === 'Admin') {%>
    <div>This is only shown to admin.</div>
<% } %>

This type of checks can also be done in the actual View itself to limit certain functionalities based on the user, etc.

Upvotes: 1

Related Questions