Gem 写一点 CanCan 结合数据库使用的简单实现

beiersi · 2012年10月09日 · 最后由 diguage 回复于 2015年09月20日 · 8150 次阅读
本帖已被管理员设置为精华贴

一个中小型旅行社使用的一个简易 CRM 系统。需要管理员能通过页面来对用户授权,颗粒精细到 action 即可。相关的 Gems 如下:

+ rails 3.2.8
+ devise 2.1.2
+ simple_form 2.0.2
+ cancan 1.6.8

思路: 使用 CanCan 实现基于数据库的授权。可以参考 Cancan 的 wiki 上这篇文章 [https://github.com/ryanb/cancan/wiki/Abilities-in-Database]。 用表 permissions 保存所有的权限,与 users 的关系是 has_and_belongs_to_many,在 Ability.rb 中处理一下 user.permissions 既可。

下面是具体实现的几个基本步骤: Gemfile 和 devise 的配置过程省略。

创建 model Permission

rails g model Permission action subject description

创建 has_had_belongs_to_mang 中间表。

rails g migration UsersHABTMPermissions

编辑 db/migrate/xx_users_habtm_permissions.rb

class UsersHabtmPermissions < ActiveRecord::Migration
  def up
    create_table :permissions_users, :id => false do |t|
      t.references :permission
      t.references :user
    end
    add_index :permissions_users, [:user_id, :permission_id]
    add_index :permissions_users, [:permission_id, :user_id]
  end

  def down
    drop_table :permissions_users
  end
end

生成表

rake db:migrate

编辑 app/models/permission.rb,和 app/modles/user.rb,加入 habtm 关系

# app/models/user.rb
class User < ActiveRecord::Base
  .
  .
  .

  has_and_belongs_to_many :permissions
end

# app/models/permission.rb
class Permission < ActiveRecord::Base
  attr_accessible :action, :description, :subject
  has_and_belongs_to_many :users
end

创建 app/models/ability.rb

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new

    ## 指定超级用户
    if user.id == 1
      can :manage, :all
    else
      user.permissions.each do |p|
        begin
          action = p.action.to_sym
          subject = begin
                      # RESTful Controllers
                      p.subject.camelize.constantize
                    rescue
                      # Non RESTful Controllers
                      p.subject.underscore.to_sym
                    end
          can action, subject
        rescue => e
          Rails.logger.info "#{e}"
          Rails.logger.info "#{subject}"
        end
      end
    end
  end
end


这样基本的步骤就完成了。然后我们手动把权限一条一条的加上去,并对用户授权

举例:

## 增加权限
Permission.create(:action => 'manage', :subject => 'user', :description => '用户管理')
Permission.create(:action => 'manage', :subject => 'hotel', :description => '酒店管理')
Permission.create(:action => 'read', :subject => 'hotel', :description => '酒店查看')
Permission.create(:action => 'index', :subject => 'hotel', :description => '酒店列表查看')
## 给用户授权
user = User.find 10
user.permissions = [...]

最后不要忘记在相应的 controller 中加入:

## 第一种情况 RESTful Controllers
load_and_authorize_resource
# 或者
authorize_resource

## 第二种情况 Non RESTful Controllers 
authorize_resource :class => false

以上是本人在使用 Cancan 结合数据使用的简单实现,限于篇幅,用户授权和权限列表的页面操作就省略了,都是比较基础的 CRUD 操作。

请教一下 authorize_resource :class => false 是将所有的 action 都验证一遍吗?

@zlx_star 是的,authorize_resource 会对所有 action 都进行验证。 可以加上 skip_authorize_resource 过滤某些 action 比如:

class XxxController < ApplicationController
  authorize_resource
  skip_authorize_resource :only => :index
end

谢谢,我英文不好,对我很有帮助。

受益匪浅,谢谢了

您好 能问一下 action 的种类一共有几种呢?有没有详细的介绍?

Mark 一下,研究研究 Cancancan 和 Pundit。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号