Rails插件:CanCan权限验证插件学习总结

Posted on 2011-09-05 14:08  bendanchenzhicheng  阅读(5023)  评论(1编辑  收藏  举报

Rails插件:CanCan权限验证插件学习总结

CanCanrails下的一个用于限制用户对网站资源访问控制权限的插件,所有的权限都定义在一个文件中(ability.rb)。
1.
安装
gemfile中加上gem ‘cancan’
2.
注意要点
注意:CanCan需要调用controller中的current_user方法来获取当前登录的用户对象,当然也允许用户修改这个方法名称,如下:
(1)
ApplicationController中定义如下方法
private
def current_ability
@current_ability ||= AccountAbility.new(current_account)
#
上一句话将会将CanCan调用Ability类修改为调用AccountAbility类,并且通过current_account获取当前登录用户
end
(2)
修改Ability参数,在某些情况下会要根据用户及其他相关信息进行权限控制,如限制某个IP的用户访问,因为Ability类中没有request对象,因此需要从controller中传递给Ability,方法如下:(同理可用于sessioncookie
(A)
ApplicationController中定义如下方法
private
def current_ability
@current_ability ||= Ability.new(current_user, request.remote_ip)
end
(B) Ability
类如下:
class Ability
include CanCan:Ability
def initialize(user, ip_address)
can :create, Comment unless BLACKLIST_IPS.include? ip_address
end
end

3.使用方法
(1)
定义Ability类,可以手动建立(model目录下),也可以通过命令行建立。
命令行方法为:rails g cancan:ability
(2)
检测和认证权限的函数
(A)
controllerview中使用can?, cannot?
(B) authorize!
方法只能用于controller
(C)
可以在controler中使用load_and_authorize_resourceauthorize_resource,本方法如要用于RESTful样式的controller中,它将会为所有action添加个before_filter来检测权限,不同的是load_and_authorize_resource会先加载本类model的值。
(3)
处理未授权的访问的方法
如果权限认证失败,cancan会抛出一个CanCan::AccessDenied的异常,你可以在ApplicationController中捕获它来显示自己内容。
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, :alert => exception.message
# exception.action, exception.subject
end
(4)
设置对应用程序所有action都检查权限,可以在ApplicationController中添加check_authorization,如果在个别的controller中需要跳过验证,可以在该controller中添加skip_authorization_check
注意:使用check_authorization可以跟 if unless 条件,如:
check_authorization if||unless) => :
函数

4.如何定义Ability
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new #
防止用户未登录
if …..#
判断当前用户是否时管理员
can :manage, :all #
可以管理所有资源
else
can :read, :all #
可以读取所有资源
end
end
end

(1) can函数
can
方法, 对象[, 对象ID]
这里的方法通常为:read, :create, :update:destroy, 但是它可以为任何方法。对象可以是model的对象或类名
(A)
可以通过alias_action来将几个方法合并成一个方法。如下:
class Ability
include CanCan::Ability
def initialize(user)
alias_action :update, :destroy, :to => :modify
can :modify, Comment
end
end
(B)
传递数组
can [:update, :destroy], [Article, Comment]
(C)
根据条件判断权限
#
允许查看projectsactive=true,并且user_id为当前登录用户的project
can :read, Project, :active => true, :user_id => user.id
#
允许查看projectsbelongs_tocategory(visible = true)project
can :read, Project, :category => {:visible => true}
#
允许查看projectspriority1-3之间的project
can :read, Project, :priority => 1..3
#
允许查看projectsbelongs_togroup(groupid在用户所属groupid之中)project
can :read, Project, :group => {:id => user.group_ids}
(D)
根据block条件来判断权限
#
允许更新所有project.priority < 3project
can :update, Project do |project|
project.priority < 3
end

注意:使用block时,内部只能用当前类的对象,如上个例子只能使用project对象,其他对象都不行,如user等。

5.controller中验证的函数
(1) authorize!
方法, 对象
调用本方法检测无权限时,会抛出一个CanCan::AccessDenied异常
(2) authorize_resource
本方法会自动将当前controller中所有action都加上before_filter来调用authorize!来检测权限
(3) load_and_authorize_resource
包含(load_resourceauthorize_resource)
authorize_resurce类似,只是会在验证之前根据controller的名字去自动生成对应的model的对象,:
class ProductsController < ActiveRecord::Base load_and_authorize_resource def index #
注意生成对象的名字和controller是同名的 # @products = Product.accessible_by(current_ability) end def show # @products = Products.find(params[:id]) end end 6.controller中自定义检测对象的类名 load_and_authorize_resource :class => ‘Store::Product’

6.controller中加载验证过程覆盖的方法
class BooksController < ApplicationController before_filter :find_my_book, nly => :show
load_and_authorize_resource

private
def find_my_book
@book = Book.released.find(params[:id])
#
这里会将load_resource自动生成的@book换成自己的
end
end
注:如果只是使用了authorize_resource来验证权限,那么必须使用prepend_before_filter来调用自己的代码

7.当前用户更新自己的信息时,最好清空下ability和当前用户,防止有缓存存在
if @user.update_attributes(params[:user])
@current_ability = nil
@current_user = nil
end

8.无权限的异常捕捉
(1)
错误信息的自定义
(A) authorize! :read, Article, :message => “Unable to read the article.”
(B) raise CanCan::AccessDenied.new(“Not authorized!”, :read, Article)

(C) 修改语言包config/locales/en.yml
en:
unauthorized:
manage:
all: “Not authorized to %{action} %{subject}”
user: “Not allowed to manage other user accounts”
update:
project: “Not allowed to update the project”

9.Ability权限的调试方法
user = User.first # fetch any user you want to test abilities on
project = Project.first # any model you want to test against
ability = Ability.new(user)
ability.can?(:create, project) # see if it returns the expected behavior for that action
ability.can?(:index, Project) # see if user can access the class
Project.accessible_by(ability) # see if returns the records the user can access
Project.accessible_by(ability).to_sql # see what the generated SQL looks like to help determine why it’s not fetching the records you want
另外可以将无权限的异常写入日志文件在rescue_from CanCan:AccessDenied中添加:
Rails.logger.debug “Access denied on #{exception.action} #{exception.subject.inspect}”

10.Ability权限设置的技巧
(1)
可以管理项目的相关信息,但是不能删除项目
can :manage, Project
cannot :destroy, Project
(2)
可以管理自己的项目,但是不能编辑已经锁定的项目
can :manage, Project, :user_id => user.id
can :update, Project do |project|
!project.locked?
end
(3) RESTful
格式的action名称,有以下注意点:
:read
等于 :index, :search, :show
:update
等于 :update, :edit
:create
等于 :new, :create
:delete
等于 :destroy, :delete

11.根据用户权限获取数据
通常使用accessible_by(current_ability)来获取当前用户可以:read的信息,当然当使用了load_resource后,可以不需要自己获取。
也可以修改默认的:read,如accessible_by(current_ability, :update)来获取当前用户可以编辑的数据

12.带角色的权限设置
(1)
一个用户一个角色,通过用户表中role的字段来存储,直接在Ability中用角色名称判断
(2)
多个用户对应多个角色,如:
(A)
用到的表如下
用户表:users
字段:name:string, password:string
角色表:roles
字段:name:string
用户和角色关系表:users_roles_relations
字段:role_id:integer, user_id:integer
权限表:permissions
字段:action:string, subject_class:string, role_id:integer

(B) models
class User
has_many :users_roles_relations
has_many :roles, :through => users_roles_relations
end
class Role
has_many :users_roles_relations
has_many :users, :through => users_roles_relations
has_many :permissions
end
class UsersRolesRelation
belongs_to :role
belongs_to :user
end
class Permission
belongs_to :role
end

(C) ability
class Ability
include CanCan::Ability
def initialize(user) #
这里的user是由cancan自动调用current_user来获取到的,最好定义在ApplicationController
user ||= User.new
if user.roles.find_name(‘admin’) #
当前用户有角色名称为admin的角色时,有所有权限
can :manage, :all
else
user.roles.each do |role|
role.permissions.each do |permission|
can permission.action.to_sym, permission.subject_class.constantize
end
end
end
end
end

(D) controller中调用相应的验证函数就行了。
(E)
无权限异常的捕捉,上述也已讲过,只用在ApplicationController中添加rescue_from CanCan::AccessDenied就行了

Copyright © 2024 bendanchenzhicheng
Powered by .NET 9.0 on Kubernetes