Reputation: 5319
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
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
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