使用CanCanCan进行权限管理(一)

2016-12-16 10:10:08来源:作者:王梦琪的博客人点击

为什么要使用Cancancan

网站在发展的过程中,用户角色会不断的增加,并且会出现很多细分的权限,此时如果每次都在相应的controller和view里写判断,会变得非常冗杂,后期很难进行维护。针对这种情况,cancancan为我们提供了非常好的一种解法,详见 Github官方文档。

举一下我们自己的例子:

我们做的是一个在线编程教育的网站,之前是有三种角色的:admin,VIP和普通用户,最初课程只有草稿/公开两种状态,在上线前增加了一下状态:上锁/未上锁,付费/免费。

于是针对用户能否查看课程,我写了以下的权限判断,看起来比较乱,但是能够快速解决问题。

def check_course_validation(course) if !current_user.is_admin if course.is_locked if course.paid_courses && !current_user.valid_member? redirect_to vip_to_payment_path else redirect_to dashboard_path flash[:alert] = "暂无权限" end else if course.paid_courses && !current_user.valid_member? redirect_to vip_to_payment_path end end endend

上线后,用户基数加大,管理者身份里,单admin一个权限已经不合适了,需要再加editor的角色,editor有很多细分的权限,比如可以管理课程,但不能新增删除课程。

此时再在controller里去判断权限就不合适了,使用cancancan来进行权限管理就合理很多。

cancancan的基础步骤

说明:下文中,注的内容如果看不懂可以忽略掉,在实作的过程中再理解。

第一步:安装

在Gemfile里添加 gem 'cancancan',然后在终端执行 bundle install,成功后执行

rails g cancan:ability

注:这样会生成一个ability.rb的文件,简单来说,我们会把网站所有的权限定义在这个ability文件里,在controller里和view里不用在权限判断了,只需要在view里检查是否有权限,在controller设置一下,更棒的是,view和controller里的权限是一致的。

第二步:在ability里定义用户角色相应的权限

在app/models/ability.rb里定义用户角色和权限,如果只有两种用户user,admin:

class Ability include CanCan::Ability def initialize(user) if user.blank? # 未登录 cannot :manage, :all elsif user.admin? # admin can :manage, :all else can :manage, Course cannot [:new, :create, :destroy], Course end end

注:

1.以上定义的内容是,未登录状态下,什么都不能做;admin可以做所有的操作, User只能管理Course,单不能对Course执行以下三个(:new, :create, :destroy)的操作

2.all 是指所有 object (resource)

3.cancancan 预设了几个action的组合方便我们使用:

# :manage: 是指这个 controller 內所有的 action # :read : 指 :index 和 :show # :update: 指 :edit 和 :update # :destroy: 指 :destroy # :create: 指 :new 和 :crate

can :manage, :all 指的是可以管理全部的内容

4.权限的顺序很重要,如果重叠,下面的会覆盖上面的,比如

can :manage, Course cannot [:new, :create, :destroy], Course

上述说明用户不得删除/新增course

cannot [:new, :create, :destroy], Coursecan :manage, Course

但如果顺序反过来,就表明:用户可以对课程进行任意操作。

在对应的controller设置

在app/controllers/admin/courses_controller.rb里设置

class Admin::CoursesController < AdminControllerload_and_authorize_resource def new @course = Course.new end end

此时权限就识别好了,如果你测试会发现,user已经无法删除某一个course了。

注:

cancancan是根据controller判断的,而非model。 cancancan 很聪明得会在controller里识别同名的资源,在CoursesController里会load和authorize @course, 如果你希望比如在SyllabusController里去识别 @course,你可以这样写 class Admin::SyllabusController < AdminController load_and_authorize_resource :course ...end load_and_authorize_resource:指的是两件事load_resource和authorize_resource.关于这个,xdite有一篇文章, Cancan 實作角色權限設計的最佳實踐(2),在此不再赘言。 需要补充说明的是,请尽量使用 load_and_authorize_resource。 如果在上述controller里直接使用 authorize_resource, cancancan是找不到@course这个instance的,所以要么使用 load_and_authorize_resource或者在authorize_resource生效前,使用before_filter塞入一个@course的instance 请注意:strong_params的命名要规范。比如course_params不可写作courses_params,不然cancancan无法识别。 在View里进行检查

在app/views/admin/courses/index.html.erb里

此时,如果我们在ability里定义用户能够删除course,则显示这个按钮,如果用户没有权限,前台就不会显示了。

增加报错提示

我们可以在ApplicationController里定义

class ApplicationController < ActionController::Base rescue_from CanCan::AccessDenied do |exception| redirect_to root_path, :alert => exception.message end end

这时如果用户进入到权限之外的网址,就会被导至root path,并且看到相应报错了。

下一篇我会写一些具体情况 如nested resource,shallow routes, hash conditions等。

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台