When building a Web system, I think there are relatively many requests to "manage authority for each user."
In Ruby on Rails, you can use a Gem called cancancan to manage permissions, but this Gem manages execute permissions (read / write) on the Model. The basic usage is to do.
This time, there is a requirement that "I want to manage the execution authority of API", and I investigated the method, so I summarized it.
Before getting into the main subject, I will briefly introduce the general usage of cancancan (model-based control). (Almost a Japanese translation of the Gem Readme)
Add the following to your Gemfile.
gem 'cancancan'
The privileges granted to users are defined in the ʻAbility class. First, create the ʻAbility
class with the following command.
rails g cancan:ability
As an example, control the execute permission of the model Post.
class Ability
include CanCan::Ability
def initialize(user)
can :read, Post, public: true # public=Anyone can see the true record
if user.present? #Define additional login user privileges
can :read, Post, user_id: user.id # user_You can also refer to records whose id is your own
if user.admin? #Define additional permissions for the admin user
can :read, Post #All records can be referenced
end
end
end
end
cancancan has a rich wiki with detailed definitions. Defining Abilities - cancancan
<% if can? :read, @post %>
<%= link_to "View", @post %>
<% end %>
You can check if the user has read permission for the variable @post
with can?: read, @post
.
In the case of the above example, the link is displayed only when you have the reference authority of @ post
.
For more information on the helpers available in the view, see the following pages on the wiki:
Checking Abilities - cancancan
As a prerequisite, the method current_user
must be able to reference the logged-in user.
Pre-install Gem for authentication such as Devise and Authlogic.
def show
@post = Post.find(params[:id])
authorize! :read, @post # current_user@Error if post cannot be referenced
end
If you write load_and_authorize_resource
, before_action
will be added to load the resource and check the authority according to the controller name.
You can use load_and_authorize_resource
to prevent the situation where you forgot to write ʻauthorize!` In the action you added later and missed the permission check.
class PostsController < ApplicationController
load_and_authorize_resource
def show # GET /posts/:post_Called when accessing id
# before_Do the following in action
# @post = Post.find(params[:post_id])
# authorize! :show, @post
end
end
The following aliases are internally cut in cancancan.
alias_action :index, :show, :to => :read
alias_action :new, :to => :create
alias_action :edit, :to => :update
So, for example, ʻauthorize!: Show, @post and ʻauthorize!: Read, @post
will give the same result.
cf. Action Aliases - cancancan
load_and_authorize_resource
can be divided into load_resource
and ʻauthorize_resource. In the above example,
@post = Post.find (params [: post_id])part of
load_resource is
before_action, and ʻauthorize_resource
is ʻauthorize!: Show, @ post part of
before_action. `Is added.
cf. Authorizing controller actions - cancancan
This is the main subject.
As an example, suppose you have defined two actions in your Post
controller: show
and ʻupdate`.
class PostsController < ApplicationController
def show # GET /posts/:post_API to call by id
end
def update # PUT /posts/:post_API to call by id
end
end
Allows the admin user to execute both GET / posts /: post_id
and PUT / posts /: post_id
, and other users to execute only GET / posts /: post_id
.
class Ability
include CanCan::Ability
def initialize(user)
can :show, :post # GET /posts/:post_id can be executed by anyone
if user.admin? #Define additional permissions for the admin user
can :update, :post # PUT /posts/:post_id can only be executed by admin user
end
end
end
The purpose is to control the execution of the API, so check with the controller, not the view.
class PostsController < ApplicationController
authorize_resource class: false
def show # GET /posts/:post_API to run by id
# before_Do the following in action
# authorize! :show, :post
end
def update # PUT /posts/:post_API to run by id
# before_Do the following in action
# authorize! :update, :post
end
end
The key is to use ʻauthorize_resource class: false instead of
load_and_authorize_resource`.
Considering the case of show
of PostsController
as an example, ʻauthorize_resource seems to add
before_action` that works with the following logic.
(I didn't follow the source properly, so it may be different exactly)
if @Is a resource assigned to post?
authorize! :show, @post
elsif 'class: false'Is not specified?
authorize! :show, Post
else
authorize! :show, :post
end
If you use load_and_authorize_resource
, the resource will be put in @ post
, so the permission check of @ post
will run.
Also, if you do not specify class: false
, the model Post permission check will run.
That's why we use ʻauthorize_resource class: false`.
I searched online for how to manage API execution privileges, but I couldn't find anything else, so I summarized it this time. If you have any mistakes, please feel free to comment.
I think these requirements will increase with the popularity of microservices. If you find yourself in a similar situation, I would appreciate it if you could refer to it.
Recommended Posts