Role-based Authorization with Pundit

參考: http://www.xyyz.me/2015/07/24/role-based-authorization-with-pundit.html

本文將介紹: 在 Rails 應(yīng)用中, 如何使用 Pundit 實現(xiàn)一個基于角色的授權(quán)系統(tǒng).
數(shù)據(jù)模型
+------+ +------+ +------------+| | N N | | 1 N | || User |<-------->| Role |<-------->| Permission || | | | | |+------+ +------+ +------------+

User 和 Role 是多對多的關(guān)系, Role 和 Permission 是一對多的關(guān)系. Permission 的定義包含兩個字段: action
和 resource
, 分別與 Rails 的 Controller Action 和 Model 對應(yīng).
Model 關(guān)系定義:
class User < ActiveRecord::Base has_and_belongs_to_many :roles has_many :permissions, through: :rolesend

class Role < ActiveRecord::Base has_many :permissions, dependent: :destroy has_and_belongs_to_many :usersend

class Permission < ActiveRecord::Base belongs_to :role has_many :users, through: :roleend

權(quán)限定義
為了方便在角色管理時能夠列出可選擇的權(quán)限點, 權(quán)限點的定義需要通過某種方式存儲起來:
class ApplicationPolicy class << self def actions @actions ||= [] end def permit(action_or_actions) acts = Array(action_or_actions).collect(&:to_s) acts.each do |act| define_method("#{act}?") { can? act } end actions.concat(acts) end end private def can?(action) permission = { action: action, resource: record.is_a?(Class) ? record.name : record.class.name } user.permissions.exists?(permission) endend

在 ApplicationPolicy
里定義一個 permit
方法 (類方法) 用來定義和保存權(quán)限點,can?
方法用來做權(quán)限檢查.
然后就可以像這樣聲明權(quán)限點:
class ResourcePolicy < ApplicationPolicy permit [:read, :create, :update, :destroy]end

這些 Action 就會被保存到 ResourcePolicy.actions
里.
另外還需要兩個方法 policies
和 resource
:
class ApplicationPolicy class << self def policies @policies ||= Dir.chdir(Rails.root.join('app/policies')) do Dir['*/_policy.rb'].collect do |file| file.chomp('.rb').camelize.constantize unless file == File.basename(FILE) end.compact end end def resource name.chomp('Policy') end endend

分別用來獲取所有的 Policy 和 每個 Policy 對應(yīng)的 resource (這兩個方法是通過簡單的命名規(guī)則實現(xiàn)的, 靈活性會差一點).
角色與權(quán)限
在角色管理中, 可以像這樣列出所有可選擇的權(quán)限點:
<% ApplicationPolicy.policies.each do |policy| %> <% resource = policy.resource %> <div> <span><%= resource %></span> <% policy.actions.each do |action| %> <% checked = role.permissions.exists?(action: action, resource: resource) %> <% value = "#{action}##{resource}" %> <%= f.check_box :permissions, { multiple: true, checked: checked }, value, nil %> <%= f.label :permissions, value, value: value %> <% end %> </div><% end %>

角色與用戶
在用戶管理中, 可以這樣為用戶指定角色:
<div> <%= f.label :roles %><br /> <%= f.collection_check_boxes :role_ids, Role.all, :id, :name %></div>

參考項目
這個系統(tǒng)的完整實現(xiàn)請參考此項目 (mxyzm/oh_my_user) 的后臺管理部分.
參考資料
利用 cancan 實現(xiàn)一個優(yōu)雅可擴(kuò)展的角色管理系統(tǒng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容