Hướng dẫn xác thực người dùng web bằng gem cancan và cài đặt input form html bằng gem ckeditor
**1 Gem cancan ** Đây là gem thư viện rất được yêu thích sử dụng cho việc xác thực cũn như phân quyền các chức năng cho các level người dùng. Với cách cài đặt và sử dụng khá dễ hiểu. 1.1 Cài đặt và file cấu hình Trước hết để cài đặt gem cancan này chúng ta cần phải thêm trong gemfile gem ...
**1 Gem cancan **
Đây là gem thư viện rất được yêu thích sử dụng cho việc xác thực cũn như phân quyền các chức năng cho các level người dùng. Với cách cài đặt và sử dụng khá dễ hiểu.
1.1 Cài đặt và file cấu hình
Trước hết để cài đặt gem cancan này chúng ta cần phải thêm trong gemfile
gem 'cancancan', '~> 1.9' đối với rails 3 trở lên, sau đó chạy bundle để download gem và cài đặt
Tiếp theo là tạo file dùng để định nghĩa các quyền hạn của người dùng bằng cách chạy lệnh command
rails g cancan:ability
lệnh này sẽ tự động tạo ra file app/models/ability.rb, đây sẽ là file chúng ta thiết lập các quyền cho người dùng trên hệ thống web
class Ability include CanCan::Ability def initialize(user) user ||= User.new # guest user (not logged in) if user.admin? can :manage, :all else can :read, :all end end end
Đây là đoạn code mẫu mà file ability được tạo ra. Đọc code này ta có thể dễ dàng hình dung ngay ra được ý nghĩa của nó, giống như là ta đọc 1 đoạn văn bản vậy.
Ở đây cancan sẽ kiểm tra quyền của model user. Nếu hàm user.admin? có giá trị true thì user đó có mọi quyền hạn cho mọi đối tượng, còn nếu không thì user chỉ có thể xem tất cả các thông tin mà thôi.
ta có thể dễ thấy 3 trường tạo nên 1 lệnh định nghĩa quyền của người dùng.
thứ nhất đó là "can" để chỉ khả năng có quyền làm , ngoài ra để định nghĩa phủ định 1 quyền nào đó ta sẽ dùng "cannot" Thứ 2 là action, quyền đó là gì, ở đây cacan có mọi quyền cơ bản là create, update, read, delete, ngoài ra còn có 1 số quyền khác như invite... mà "manage" là 1 quyền đặc biệt bao gồm tất cả các quyền đã nói trên. thứ 3 là đối tượng chịu áp dụng (tên model) , all là tất cả các model, Ví dụ:
can :manage, Article # user can perform any action on the Article can :read, :all # user can read any object can :manage, :all # user can perform any action on any object
ngoài ra ta có thể nhóm các quyền và các đối tượng chịu áp dụng vào 1 mảng khi khai báo chung với các quyền giống nhau
can [:update, :destroy], [Article, Comment] Ngoài ra ta còn có thể thêm các điều kiện đi kèm cho khai báo quyền hạn với 1 đối tượng nào đó vào cuối dòng.
ví dụ:
can :read, Project, :active => true, :user_id => user.id
ở đây ta có thể thấy là người dùng này có quyền đọc project , còn ":active => true, :user_id => user.id" là điều kiện, nôm na là người dùng này có quyền xem project với điều kiện trường active của project là true và project có trường user_id = id của người dùng, tương đương project là của người đó.
ngoài ra còn có thêm 1 số lựa chọn nữa các bạn có thể tham khảo tại đây
!lưu ý về việc create/update đối tượng thì cancan sẽ tự động check các strong params kiểu như sau:
-
create_params hoặc update_params (tùy theo controller nào được gọi tới)
-
<model_name>_params ví dụ micropost_params (model có tên là Micropost)
-
resource_params
Nếu bạn có khai báo 1 strong params nào khác khoài 3 loại trên trong controller thì bạn phải khai báo params đó với cancantheo ví dụ sau
class ArticlesController < ApplicationController load_and_authorize_resource param_method: :my_sanitizer def create if @article.save # hurray else render :new end end private def my_sanitizer params.require(:article).permit(:name) end end
1.2 Kiểm tra quyền
Ở đây cancan hỗ trợ việc kiểm tra ở cả view và controller
với View:
<% if can? :update, @article %> <%= link_to "Edit", edit_article_path(@article) %> <% end %>
ta dùng "can?" để kiểm tra thẩm quyền của user với @article đó với action là update (đã được khai báo ở file ability trên) rồi trả ra kết quả true hoặc false tương ứng.
Với Controller:
chúng ta dùng hàm "authorize!" để kiểm tra quyền và trả về lỗi nếu quyền đó là không được phép/ hoặc chưa được khai báo.
def show @article = Article.find(params[:id]) authorize! :read, @article end
Ngoài ra cancan còn hỗ trợ hàm "load_and_authorize_resource" để áp dụng việc check quyền đối với mọi controller, thường thì hàm này được khai báo trong class ApplicationController hoặc ở file BaseController mà các controller khác kế thừa
class ArticlesController < ApplicationController load_and_authorize_resource def show # @article is already loaded and authorized end end
để tiện cho việc dùng
load_and_authorize_resource thì Can can cũng hỗ trợ hàm
skip_load_and_authorize_resource để loại bỏ việc xác thực đối với 1 số controller đặc biệt như các trang static page, trang signin, signup ...
Thêm vào đó ta có thể giới hạn các action chịu ảnh hưởng các hàm đó bằng thêm option only [action]. giống như dùng "before_action"
load_and_authorize_resource :only => [:index, :show]
1.3 Xử lý các trường hợp không hợp lệ
Dối với các action không hợp lệ từ người dùng, cancan hỗ trợ cho chung ta việc config để chuyển tiếp tới 1 trang thông báo nào đó, ngoài ra có thể thêm các action khác tùy theo yêu cầu. Như ví dụ dưới là sẽ chuyển tới trang chính của web nếu như các truy cập là không hợp lệ.
class ApplicationController < ActionController::Base rescue_from CanCan::AccessDenied do |exception| redirect_to root_url, :alert => exception.message end end
Và để chắc chắn rằng mọi controller đều được kiểm tra quyền chúng ta có thể dùng
check_authorization trong class ApplicationController
class ApplicationController < ActionController::Base check_authorization end
Và nếu nuốn loại bỏ việc check quyền này ta dùng hàm
skip_authorization_check
**2. Gem ckeditor **
giới thiệu: đây là 1 gem hỗ trợ việc tạo ra đoạn text theo dạng html, giúp cho việc input dữ liệu dạn text với yêu cầu cao về giao diện.
2.1 cài đặt
như thường lệ để cài đặt gem nà cho rails ta thêm
gem 'ckeditor' vào file Gemfile
với trường hợp cần việc upload file (như là ảnh) vào text, chúng ta cần thêm 1 số gem hỗ trợ việc tạo model và lưu file:
ActiveRecord (paperclip, carrierwave, dragonfly) Mongoid (paperclip, carrierwave, dragonfly) trên là các gem hỗ trợ ứng với tên kiểu database.
Với:
ActiveRecord + paperclip:
the thêm gem
gem 'paperclip'
và dùng lệnh này chạy trên command để sinh ra file model, config cần thiết
rails generate ckeditor:install --orm=active_record --backend=paperclip
tương tự với:
ActiveRecord + carrierwave
gem 'carrierwave' gem 'mini_magick' rails generate ckeditor:install --orm=active_record --backend=carrierwave Mongoid + paperclip
gem 'mongoid-paperclip', :require => 'mongoid_paperclip' rails generate ckeditor:install --orm=mongoid --backend=paperclip Mongoid + carrierwave
gem 'carrierwave-mongoid', :require => 'carrierwave/mongoid' gem 'mini_magick' rails generate ckeditor:install --orm=mongoid --backend=carrierwave
Ở trong github thực hành tôi dẽ dùng ActiveRecord + carrierwave
Sau khi chạy lệnh trên hệ thống sẽ tự tạo ra file model trong thư mụcapp/models/ckeditor.
Kế tiếp bạn cần thêm đường dẫn config cho ckeditor trong file configapplication.rb:
config.autoload_paths += %W(#{config.root}/app/models/ckeditor) thêm đường dẫn trong file config/routes: mount Ckeditor::Engine => "/ckeditor"
2.2 Sử dụng
Thêm ckeditor javascripts vào file app/assets/javascripts/application.js
//= require ckeditor/init trong view để dùng ckeditor cho việc tạo dữ liệu html ta dùng option "cktext_area"
<%= form_for @page do |form| -%> ... <%= form.cktext_area :notes, :class => 'someclass', :ckeditor => {:language => 'uk'} %> ... <%= form.cktext_area :content, :value => 'Default value', :id => 'sometext' %> ... <%= cktext_area :page, :info, :cols => 40, :ckeditor => {:uiColor => '#AADC6E', :toolbar => 'mini'} %> ... <% end %>
ngoài ra để giảm thời gian chờ khi dùng ckeditor, chúng ta có thể giới hạn các plugin/ ngôn ngữ được load bằng cách thêm config vào file config/initializers/ckeditor.rb
Ckeditor.setup do |config| config.assets_languages = ['en', 'fr'] config.assets_plugins = ['image', 'smiley'] end
2.3 mở rộng
ckeditor sử dụng với Formtastic integration thông qua cách khai báo:
<%= form.input :content, as: :ckeditor %> <%= form.input :content, as: :ckeditor, input_html: { ckeditor: { height: 400 } } %>
với SimpleForm integration
<%= form.input :content, as: :ckeditor, input_html: { ckeditor: {toolbar: 'Full'} } %>
Khi sử dụng cùng với cancan
thêm config vào file config/initializers/ckeditor.rb để xác thực việc ckeditor sẽ đc dùng với cancan
Ckeditor.setup do |config| config.authorize_with :cancan end
Sau đó khao báo quyền trong file ability của cancan nhu bình thường
can :access, :ckeditor # quyền sử dụng ckeditor
các quyền cho việc sử dụng file, ảnh qua ckeditor
can [:read, :create, :destroy], Ckeditor::Picture can [:read, :create, :destroy], Ckeditor::AttachmentFile
ngoài ra vì ckeditor lưu theo dạng html nên để hiện theo đúng kiểu html thì ờ view chúng ta dùng hàm sanitize . ví sụ trường content của @micropost, ở view t dùng như sau:
<%= sanitize @micropost.content %>
Sau đây là link project sample_app đã được áp dụng để test với 2 gem trên
https://github.com/leanh173/sample_app/tree/develop