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


    (转) http://www.cnblogs.com/bendanchenzhicheng/archive/2011/09/05/2167451.html

    作者: fandyst
    出处: http://www.cnblogs.com/todototry/
    关注语言: python、javascript(node.js)、objective-C、java、R、C++
    兴趣点: 互联网、大数据技术、大数据IO瓶颈、col-oriented DB、Key-Value DB、数据挖掘、模式识别、deep learning、开发与成本管理
    产品:
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
  • 相关阅读:
    Java算法练习——整数反转
    Java算法练习—— Z 字形变换
    Java算法练习——最长回文子串
    vs code自动生成html代码
    thinkphp整合后台模板
    composer安装后台模板
    composer(作曲家)安装php-ml
    两个网站
    PHP的开源产品discuz
    onethink中的用户登录session签名
  • 原文地址:https://www.cnblogs.com/ToDoToTry/p/2207047.html
Copyright © 2011-2022 走看看