權限控制[1] CanCan + Rolify + Devise

用Gem進行安裝

Reference:

說明

  • 使用devise、cancan和rolify組件建立用戶權限模型的說明。
    devise:負責用戶註冊、登錄、退出、找回密碼等操作。 devise_github

  • cancan:負責角色建立、對角色授權、在頁面中根據授權是否顯示元素,以及模型中超出授權時拋出異常。 cancan

  • rolify:負責將用戶與角色關聯。rolify_github
    在Gemfile中添加如下信息

1. 安裝devise, rolify, cancan

[Gemfile]
gem 'devise' 
gem "rolify" 
gem 'cancan' 

然後在命令行中,用 $bundle install 進行安裝。

2. Devise - install

$ rails generate devise:install

並按照提示,進行相關配置

esxi23v113@esxi23v113:~/Aptana Studio Workspace/blog$ rails generate devise:install
Running via Spring preloader in process 15821
      create  config/initializers/devise.rb




create config/locales/devise.en.yml =============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"> rails g devise:views ===============================================================================

3.Devise - generate user

$ rails generate devise User

4.CanCan - generate ability

esxi23v113@esxi23v113:~/Aptana Studio Workspace/blog$ rails g cancan:ability
Running via Spring preloader in process 15759
      create  app/models/ability.rb

5.Rolify - generate role

esxi23v113@esxi23v113:~/Aptana Studio Workspace/blog$ rails g rolify Role User
Running via Spring preloader in process 16236
      invoke  active_record
      create    app/models/role.rb
      invoke    test_unit
      create      test/models/role_test.rb
      create      test/fixtures/roles.yml
      insert    app/models/role.rb
      create    db/migrate/20170719024020_rolify_create_roles.rb
      insert  app/models/user.rb




create config/initializers/rolify.rb =============================================================================== An initializer file has been created here: config/initializers/rolify.rb, you can change rolify settings to match your needs. Defaults values are commented out. A Role class has been created in app/models (with the name you gave as argument otherwise the default is role.rb), you can add your own business logic inside. Inside your User class (or the name you gave as argument otherwise the default is user.rb), rolify method has been inserted to provide rolify methods.

6.Run db:migrate

esxi23v113@esxi23v113:~/Aptana Studio Workspace/blog$ rake db:migrate
== 20170719023958 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0380s
== 20170719023958 CreateUsers: migrated (0.0382s) =============================
== 20170719024020 RolifyCreateRoles: migrating ================================
-- create_table(:roles, {})
   -> 0.0046s
-- create_table(:users_roles, {:id=>false})
   -> 0.0129s
-- add_index(:roles, :name)
   -> 0.0199s
-- add_index(:roles, [:name, :resource_type, :resource_id])
   -> 0.0046s
-- add_index(:users_roles, [:user_id, :role_id])
   -> 0.0041s
== 20170719024020 RolifyCreateRoles: migrated (0.0467s) =======================

7.Custom Devise controller/View

Devise會幫你生成註冊/登錄一系列的功能,你可以定製自己想要的,只需要覆蓋對應的文件or方法即可。具體參考官方文檔。此處舉例利用命令生成controller。

esxi23v113@esxi23v113:~/Aptana Studio Workspace/shop$ rails generate devise:controllers users
Running via Spring preloader in process 31906
      create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb




create app/controllers/users/omniauth_callbacks_controller.rb =============================================================================== Some setup you must do manually if you haven't yet: Ensure you have overridden routes for generated controllers in your routes.rb. For example: Rails.application.routes.draw do devise_for :users, controllers: { sessions: 'users/sessions' } end ===============================================================================

8.Select devise function module.

Devise 功能模塊:

  1. Encryptable:除了內置的Bcrypt(默認),增加支持認證機制
  2. Lockable:鎖定一定數量的失敗嘗試登錄。通過電子郵件或之後才能解鎖
  3. validatable:有效性:提供的電子郵件及密碼鑑定。它是可選的,可定製的,所以你可以定義自己的代碼。
  4. Timeoutable:在一特定時期(expires sessions)沒有活動。
  5. Trackable(跟蹤):追蹤 登錄的次數、時間戳記簽字和IP地址。
  6. Rememberable(記憶):管理產生和清除表示來自用戶保存的cookie的標記(token)
  7. Registerable(註冊):處理用戶註冊過程,也可以讓他們編輯和摧毀他們的帳戶。
  8. recoverable(重設)重置用戶密碼並且發送重置指令。
  9. Confirmable 註冊登錄認證
  10. Omniauthable: adds Omniauth (github.com/intridea/omniauth) support;
  11. Database Authenticatable:登錄時加密密碼並在數據庫中驗證用戶真實性。 (可以通過POST請求或HTTP基本認證)
  12. Token Authenticatable: 基於token的用戶登錄(also known as “single access token”)。token可以通過查詢字符串或HTTP基本身份認證。

查看User.rb

你會看到device添加的模塊,選擇你需要的即可。

class User 

9.Use sign_in / sign_out

本功能只針對本系統,本系統自己做了登錄驗證,驗證通過後,我們可以直接用sign_in(@user)方法把當前的user添加到session中,之後我們就可以用current_user查看當前登陸的用戶。

具體可參考官方API:Method: Devise::Controllers::SignInOut#sign_in




# sign_in(resource_or_scope, *args) ⇒ Object

Sign in a user that already was authenticated. This helper is useful for logging users in after sign up. All options given to sign_in is passed forward to the set_user method in warden.

Examples:

sign_in :user, @user                      # sign_in(scope, resource)
sign_in @user                             # sign_in(resource)
sign_in @user, event: :authentication     # sign_in(resource, options)
sign_in @user, store: false               # sign_in(resource, options)

10.Access Control (use rolify)

add_role :admin # 用來添加角色

has_role? :admin #用來判斷是否有這個角色

def create
    admin = Admin.new(admin_params)
    if admin.save
      admin.add_role params[:role]
      respond_to do |format|
        format.html
        format.js
      end
    else
      render 'new'
    end
  end

11.Set access in ability.rb

  • :manage: 是指這個 controller 內所有的 action
  • :read : 指 :index 和 :show
  • :update: 指 :edit 和 :update
  • :destroy: 指 :destroy
  • :create: 指 :new 和 :crate
  • :all 是指所有 object (resource)
  • 其他非RESTful的method (如:search)也可以列上去,但是要逐條列出來
  • 組合 : alias_action
     
    alias_action :update, :destroy, :to => :modify
    can :modify, Comment
class Ability
  include CanCan::Ability
  def initialize(user)
    # Define abilities for the passed in user here. For example:
    #
    #   user ||= User.new # guest user (not logged in)
    #   if user.admin?
    #     can :manage, :all
    #   else
    #     can :read, :all
    #   end
    #
    # The first argument to `can` is the action you are giving the user
    # permission to do.
    # If you pass :manage it will apply to every action. Other common actions
    # here are :read, :create, :update and :destroy.
    #
    # The second argument is the resource the user can perform the action on.
    # If you pass :all it will apply to every resource. Otherwise pass a Ruby
    # class of the resource.
    #
    # The third argument is an optional hash of conditions to further filter the
    # objects.
    # For example, here the user can only update published articles.
    #
    #   can :update, Article, :published => true
    #
    # See the wiki for details:
    # https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
    user ||= User.new
    if user.has_role? :admin
      can :manage, :all
    elsif user.has_role? :Manager
      can :read, Production
      can :update, Production 
    else
      can :read, Production
    end
  end
end

12.Access control in controller

Reference: github: authorizing-controller-actions

load_and_authorize_resource method in your controller to load the resource into an instance variable and authorize it automatically for every action in that controller

class ProductsController 

13.Access control in view

<table>
  <tbody>
    <% @productions.each do |production| %>
      <tr>
        <td><%= production.name %></td>
        <td><%= production.price %></td>
        <td><%= production.amount %></td>
        <% if can? :read,Production%>
        <td><%= link_to 'Show', production %></td>
        <% end %>
        <% if can? :update,Production%>
        <td><%= link_to 'Edit', edit_production_path(production) %></td>
        <% end %>
        <% if can? :destroy,Production%>
        <td><%= link_to 'Destroy', production, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        <% end%>
      </tr>
    <% end %>
  </tbody>
</table>
<% if can? :create,Production%>
<%= link_to 'New Production', new_production_path %>
<% end %>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章