基于活动的权限与Backbone,API设计理念?

Jon*_*ues 7 permissions design-patterns backbone.js knockout.js

我正在使用Backbone和Knockout以及Knockback(ko + bb桥库)构建一个相当大的cms类型的应用程序,我正试图找出一种抽象权限的好方法.对小说也提前抱歉.

首先,这是一个非常非标准的架构,你可能会问第二个问题 - 你为什么不使用像Ember或Angular这样更全面的东西?采取的点.这就是现在的情况.:)

所以这是我的窘境.我想在控制器和viewmodel级别获得优雅的api权限.

我有一个可供我使用的对象,如下所示:

{
   'api/pages': {
     create: true, read: true, update: true, destroy: true
   },
   'api/links': {
     create: false, read: true, update: false, destroy: false
   }
   ...
}
Run Code Online (Sandbox Code Playgroud)

所以在我的路由器/控制器中,我正在新建我的集合/模型/视图模型,然后在现有视图上调用自定义渲染方法.视图处理诸如释放视图模型之类的事情.

initialize: function() {
  this.pages = new PagesCollection();
  this.links = new LinksCollection();
},

list: function() {
  var vm = new PageListViewmodel(this.pages, this.links);
  // adminPage method is available through inheritance
  this.adminPage('path/to/template', vm); // delegates to kb.renderTemplate under the hood.
}
Run Code Online (Sandbox Code Playgroud)

所以问题就在于,这些集合是完全非结构化的,即.路由器对它们一无所知.

但我需要的是,如果您不允许查看特定资源,它将重定向到未经授权的页面.

那么通过上面的例子,我考虑过滤前后的编码?但是,您在哪里指定每个路由器方法尝试访问的内容?

list: function() {
  this.authorize([this.pages, this.links], ['read'], function(pages, links) {
    // return view.
  });
}
Run Code Online (Sandbox Code Playgroud)

以前的代码非常狡猾..

对于更简单的视图模型,我有想做这样的事情 - ala Ruby的CanCan:

this.currentUser.can('read', collection) // true or false
// can() would just look at the endpoint and compare to my perms object.
Run Code Online (Sandbox Code Playgroud)

Jon*_*ues 1

尼科什尔的回答给了我一些可以借鉴的东西。我没想到实际上会超越route自己。但这是我的解决方案。我应该在问题中提到这一点 - 但有时路由器操作需要多个集合。

这方面的代码非常粗糙,需要测试 - 但它有效!在这里摆弄

以下是相关部分 - 这两种方法负责授权。

authorize: function(namedRoute) {
  if (this.permissions && this.collections) {
    var perms = this.permissions[namedRoute];
    if (!perms) {
      perms = {};
      // if nothing is specified for a particular  route, we
      // assume read access required for all registered controllers.
      _.each(_.keys(this.collections), function(key) {
        return perms[key] = [];
      });
    }

    var authorized = _.chain(perms)
      .map(function(reqPerms, collKey) {
        var collection = this.collections[collKey],
            permKey = _.result(collection, 'url');

        // We implicitly check for 'read'
        if (!_.contains('read')) {
          reqPerms.push('read');
        }

        return _.every(reqPerms, function(ability) {
          return userPermissions[permKey][ability];
        });
      }, this)
      .every(function(auth){ return auth; })
      .value();
    return authorized;
  }
  return true;
},
route: function(route, name, callback) {
  if (!callback) { callback = this[name]; }
  var action = function() {
    // allow anonymous routes through auth check.
    if (!name || this.authorize(name)) {
      callback.apply(this, arguments);
    } else {
      this.trigger('denied');
    }
  }
  Backbone.Router.prototype.route.call(this, route, name, action);
  return this;
}
Run Code Online (Sandbox Code Playgroud)

每个控制器/路由器都继承自 perm 路由器,其中每个操作的权限都映射如下:

// Setup
routes: {
  'list'     : 'list',
  'list/:id' : 'detail',
  'create'   : 'create'
},

// Collection are registered so we can
// keep track of what actions use them
collections: {
  pages: new PagesCollection([{id:1, title: 'stuff'}]),
  links: new LinksCollection([{id:1, link: 'things'}])
},

// If a router method is not defined,
// 'read' access is assumed to be
// required for all registered collections.
permissions: {
  detail: {
    pages: ['update'],
    links: ['update']
  },
  create: {
    pages: ['create'],
    links: ['create', 'update']
  }
},
Run Code Online (Sandbox Code Playgroud)