Mac環境
Ruby 2.4.1
Rails 5.1.2
進入正題,本章主要是解決多角色權限問題,使用 devise 、 cancancan 、rolify 。
注:所有 $ 開頭的都是終端里輸入的,其它都是項目里面的文檔加入的。
1、先創建好新的項目
$ rails new demo
2、打開Gemfile,加入以下gem
gem 'devise' gem 'cancancan' gem 'rolify'
3、進入項目文件俠里
$ cd demo
4、安裝剛剛加入的gem
$ bundle install
5、安裝devise
$ rails g devise:install
6、打開config/environments/development.rb 文件,在里面輸入
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
7、打開 config/routes.rb,在里面輸入
root to: "home#index"
8、打開app/views/layouts/application.html.erb 文件,在<%= yield %>前面加入以下代碼:
<p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p>
9、在終端輸入以下代碼:
$ rails g devise:views
10、現在添加一個提前routes.rb里提到的home目錄和index文件,在終端執行以下代碼:
$ rails g controller home index
11、在終端輸入以下代碼:
$ rails g devise user
12、創建一個list列表,這個list是用scaffold(腳手架)直接產生出來,在終端下輸入以下代碼:
$ rails g scaffold list name idcard phone
13、在終端下輸入以下代碼:
$ rails db:migrate
14、打開app/controllers/lists_controller.rb 和 app/controllers/home_controller.rb,把以下代碼輸入相應的位置:
before_action :authenticate_user!
注:這個是Devise的提供的方法,驗證登錄后才能打開這個list頁面
15、增加一個注冊登錄的導航,按下方法操作,打開app/views/layouts/application.html.erb,在<%= yield %>前面輸入以下代碼:
<% if current_user %> <%= link_to('退出', destroy_user_session_path, :method => :delete) %> | <%= link_to('修改密碼', edit_registration_path(:user)) %> <% else %> <%= link_to('注冊', new_registration_path(:user)) %> | <%= link_to('登錄', new_session_path(:user)) %> <% end %>
16、接下來集成cancancan、rolify
$ rails generate cancan:ability $ rails generate rolify Role User
17、打開db/migrate/20171217141406_rolify_create_roles.rb,在最后加上[5.1]這個參數,前面20171217141406這個時間戳與你的不一樣。
class RolifyCreateRoles < ActiveRecord::Migration[5.1]
18、在終端下輸入以下代碼:
$ rails db:migrate
19、打開app/controllers/application_controller.rb,輸入以下代碼:
class ApplicationController < ActionController::Base protect_from_forgery with: :exception def after_sign_in_path_for(resource) if resource.is_a?(User) if User.count == 1 resource.add_role 'admin' end resource end root_path end end
注:以上代碼是設置第一個注冊用戶id=1時為admin管理員,當id=2時就不是admin,當我注冊第一個用戶后我就把1改成2,admin改成user,那注第2個賬號時就是user權限 ,待會user做一個比admin還低一級的權限。
20、打開app/models/ability.rb,輸入以下代碼:
class Ability include CanCan::Ability def initialize(user) if user.has_role? :admin #這里的admin權限等級最高,能增刪改查。 can :manage, :all elsif user.has_role? :user #這里的user權限等級次於admin,能增改查,沒有刪除功能。 can :manage, :all cannot :destroy, :all #這里就是去掉刪除功能。 else can :read, :all #else之后的用戶只有只讀功能。 end end end
注:上面圖片內容截圖於http://blog.xdite.net/posts/2012/07/30/cancan-rule-engine-authorization-based-library-3/
21、打開app/controllers/lists_controller.rb,增加以下代碼:
class ListsController < ApplicationController load_and_authorize_resource #這個是cancancan全局權限驗證的方法 before_action :authenticate_user! #這個是devise的登錄驗證方法
注:這里有 load_and_authorize_resource
22、打開app/controllers/application_controller.rb,增加以下代碼:
rescue_from CanCan::AccessDenied do |exception| redirect_to lists_path , :alert => exception.message exception.action, exception.subject
end
注:如果權限認證失敗,cancan會拋出一個CanCan::AccessDenied的異常,你可以在ApplicationController中捕獲它來顯示自己內容。這里引用了https://www.cnblogs.com/bendanchenzhicheng/archive/2011/09/05/2167451.html
23、打開app/views/layouts/application.html.erb,增加以下代碼:
<!DOCTYPE html> <html> <head> <title>Demo</title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <div class="container"> <div class="col-md-12"> <%= link_to '首頁', root_path %> | <% if current_user %> Welcome come <%= current_user.email %> <%= link_to '退出', destroy_user_session_path, :method => :delete %> | <%= link_to '修改密碼', edit_registration_path(:user) %> <% else %> <%= link_to '注冊', new_registration_path(:user) %> | <%= link_to '登錄', new_session_path(:user) %> <% end %> <p class="text-danger"><%= alert %></p> <%= yield %> </div> </div> </body> </html>
23、打開 app/views/home/index.html.erb,增加以下代碼:
<h1>Home#index</h1> <p>Find me in app/views/home/index.html.erb</p> <% if user_signed_in? %> <%= link_to "Lists", lists_path %> <% end %>
24、打開app/views/lists/index.html.erb,增加以下代碼:
<h1>Lists</h1> <table class="table table-bordered"> <tr> <th>Name</th> <th>Idcard</th> <th>Phone</th> <% if can? :manage, @list %> <th colspan="3"></th> <% end %> </tr> <% @lists.each do |list| %> <tr> <td><%= list.name %></td> <td><%= list.idcard %></td> <td><%= list.phone %></td> <% if can? :manage, @list %> <td><%= link_to 'Show', list %></td> <td><%= link_to 'Edit', edit_list_path(list) %></td> <% if can? :destroy, @list %> <td><%= link_to 'Destroy', list, method: :delete, data: { confirm: 'Are you sure?' } %></td> <% end %> <% end %> </tr> <% end %> </table> <% if can? :create, @list %> <%= link_to 'New List', new_list_path %> <% end %>
25、按以上的操作基本實現了三角色權限管理,現在我們打開終端,在項目內,輸入rails s,啟動服務器,打開瀏覽器,輸入http://localhost:3000,就正常顯示一個Log in的頁面。現在我們注冊一個具有admin權限的賬號;成功后,到回第19項操作,把1改成2,把admin改成user,保存,我們再注冊一個具有user權限的賬號,注冊成功后,馬上到回第19項操作,注釋掉以下代碼:
# def after_sign_in_path_for(resource) # if resource.is_a?(User) # if User.count == 2 # resource.add_role 'user' # end # resource # end # root_path # end
好了,我們現在有2個賬號,一個是admin的,一個是user的。然后把上面這個功能注釋后,以后注冊的都是只有read功能的賬號。
ok,完成。