CanCanCan:Ruby on Rails 的权限管理方案
CanCanCan:Ruby on Rails 的权限管理方案
CanCanCan 是一个 Ruby on Rails 的授权库,5,688 个 Star,用于限定用户可以访问哪些资源。

Rails 应用做到一定规模,权限控制是个绕不开的问题。不同角色的用户能看到什么、能操作什么,逻辑散落在各个 Controller 和 View 里,改一处漏一处。CanCanCan 的做法是把所有权限规则集中到一个 Ability 类里管理,避免在多个地方重复写判断逻辑。
安装
Gemfile 里加一行:
gem 'cancancan'
然后 bundle install,搞定。
定义权限
运行 rails g cancan:ability 会生成一个 Ability 类,所有权限规则写在这里:
class Ability
include CanCan::Ability
def initialize(user)
can :read, Post, public: true
return unless user.present?
can :read, Post, user: user
return unless user.admin?
can :read, Post
end
end
上面这段代码表达了三层权限:所有人都能读公开帖子,登录用户能读自己的帖子,管理员能读所有帖子。规则集中在一处,不用到处翻代码,改起来也方便。
检查权限
在 View 和 Controller 里用 can? 和 cannot? 方法判断当前用户是否有某个权限:
<% if can? :read, @post %>
<%= link_to "View", @post %>
<% end %>
也可以做条件渲染、菜单显隐,用法都一样。
查询有权限的记录
CanCanCan 有一个比较实用的功能:accessible_by。它能根据当前用户的权限规则自动过滤数据库查询,只返回用户有权访问的记录:
@posts = Post.accessible_by(current_ability)
不需要手动拼查询条件,权限规则变了,查询结果自动跟着变。这在后台管理列表页用得很多,省去了大量手写 scope 的工作。

Controller 集成
Controller 里可以手动调用 authorize! 来校验权限:
def show
@post = Post.find(params[:id])
authorize! :read, @post
end
校验失败会抛出 CanCan::AccessDenied 异常,可以在 Controller 里捕获并跳转到提示页面。
也可以用 load_and_authorize_resource,一行代码搞定整个 RESTful Controller 的资源加载和权限校验:
class PostsController < ApplicationController
load_and_authorize_resource
def show
# @post 已经加载并完成权限校验
end
def index
# @posts 已经过滤为当前用户有权限的记录
end
end
它通过 before_action 自动完成资源加载和权限检查,Controller 代码量明显减少,权限逻辑也不会重复。
适合什么场景
CanCanCan 适合中小型 Rails 项目,权限模型相对固定的场景。Ability 类用 Ruby 代码定义规则,写起来直观,维护成本低。项目支持多种数据库适配器,通过 Appraisal 工具在 CI 中对不同版本的 Rails 和数据库组合做测试。
如果项目权限模型非常复杂,需要细粒度的字段级控制,可能要考虑更重的方案比如 Pundit 或者 CASL。
CanCanCan 的前身是 CanCan,由 Ryan Bates 维护,后来原作者停止维护后由社区接手并改名为 CanCanCan,持续更新至今。
更重的方案比如 Pundit 或者 CASL。
CanCanCan 的前身是 CanCan,由 Ryan Bates 维护,后来原作者停止维护后由社区接手并改名为 CanCanCan,持续更新至今。
更多推荐
所有评论(0)