从问题到解决方案之学习sailjs的polices

1. Polices是什么,能干什么?

在sails应用中,Polices是一系列用来认证授权和访问控制的工具,能够在应用调用controlleraction之前进行拦截,做些认证授权和访问控制的逻辑处理。

2. 重现问题

问题:deploy之后不重新登录?退出登录后还可以访问页面?

错误代码例子:

'GET /koala/order': {
    view : 'koala/order',
    locals : {              // 渲染页面的数据载体
      title: 'xxx'
    }
  },

上面的例子会导致不管你是否配置了Polices,一直都可以访问koala/order渲染出来的页面,但这跟我们的需求是想违背的,因此要解决这个问题。

3. 解决问题

有问题就要解,于是解决方案来了:

api/controllers/OrderController.js文件里添加一个方法:view_order,如下:

view_order: function(req, res){
    return res.view('koala/order', {
          title: 'xxx',
    });
},

回到routes.js, 重新配置如下:

'GET /koala/order': { controller: 'OrderController', action: 'view_order' },  // 或者
'GET /koala/order': { controller: 'Order', action: 'view_order' },  // 或者
'GET /koala/order': { 'OrderController.view_order' },  // 或者
'GET /koala/order': { 'Order.view_order' }, 

为什么这样配置,就可以解决问题了呢,其实官方文档也提出“警告说明”:

Polices只能应用在controlleraction(即方法)上,而不能应用到view(视图)。就是说,如果在routes.js中配置一条路由直接指向view,那么Polices会忽略这条路由,而不会拦截。除此之外,你可以使用controller的一个action来处理页面渲染,那么action就能够被Polices拦截处理。

所以上面的代码实例就是上面引用说明的具体实践。

想想,我去!那岂不是在所有渲染页面的controller里都添加这个view_order的方法,后期维护难啊,路见不平,来改进一下吧:

|-- api
    |-- View_renderController.js    // 新增这个controller,主要负责页面渲染
|-- assets
|-- config
    |-- routes.js
|-- views
    |-- koala
        |-- order.jade

配置View_renderController

View_renderController.js配置一个渲染页面的方法,如下:

order : function (req, res) {
    res.view('koala/order', {
        title: 'xxx',
        user_name: req.session.user_name
    });
},

配置routes

routes.js配置用户访问的一条路由,如下:

'GET /koala/order': {
    controller : 'View_renderController',
    action: 'order'
},

这样子,只要在View_renderController.js中添加所有渲染的页面对应的方法,并在修改一下routes.js即可,并不会影响到其他文件,相对集中管理,有利于后期维护。

4. Polices的一些注意点

api/policies文件下定义所有的Polices文件,例如:isAuthenticated.js。注意点如下:

*是全局的policies,表示所有,全部

{
    '*': isLoggedIn  // 可以放在这里(controller外面)
    OrderController: {
        edit: 'isLoggedIn',
    }
}

或者

{
    OrderController: {
        '*': isLoggedIn  // 可以放在这里(controller里面)
        edit: 'isLoggedIn',
    }
}

内部提供两个policies(值):truefalse

  • 公共访问(允许所有访问到该action)
  • 禁止访问(禁止任何访问到该action)

每个policies文件里面应该只定义一个函数

// policies/canWrite.js
module.exports = function canWrite (req, res, next) {
    // logic code goes here .
};

在配置列表中,下面的覆盖前面相同属性的policies

{
  OrderController: {
    edit: 'isLoggedIn',
    edit: 'isAdmin'     // isAdmin会覆盖上面的isLoggedIn
  }
}

可以应用一个或以上的policies

{
  OrderController: {
    edit: ['isAdmin', 'isLoggedIn']   // 数组形式
  }
}
Spy 16 March 2015