zoukankan      html  css  js  c++  java
  • Rails插件:CanCan权限验证插件学习总结

    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就行了

  • 相关阅读:
    LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)
    LeetCode 216. 组合总和 III(Combination Sum III)
    LeetCode 179. 最大数(Largest Number)
    LeetCode 199. 二叉树的右视图(Binary Tree Right Side View)
    LeetCode 114. 二叉树展开为链表(Flatten Binary Tree to Linked List)
    LeetCode 106. 从中序与后序遍历序列构造二叉树(Construct Binary Tree from Inorder and Postorder Traversal)
    指针变量、普通变量、内存和地址的全面对比
    MiZ702学习笔记8——让MiZ702变身PC的方法
    你可能不知道的,定义,声明,初始化
    原创zynq文章整理(MiZ702教程+例程)
  • 原文地址:https://www.cnblogs.com/bendanchenzhicheng/p/2167451.html
Copyright © 2011-2022 走看看