pundit
DESCRIPTION
Pundit Simple Rails AuthorizationTRANSCRIPT
Pundit simple Rails authorization
Ruby::AZ - July 15, 2014
Bruce White Software Ops developer [email protected]
We Build Mobile App Systems
Authorization vs Authentication
Today we’re talking about authorization
• Authentication is about who you are
• Authorization is about what you can do
• To work, authorization requires authentication (need to know who you are to determine what you can do)
Rails Authorization: A Retrospective
• 10 years ago, in the beginning of The Enlightenment, authorization was a “roll your own” thing
• 4 years ago, CanCan shook the Rails world to the core
• A year ago, Pundit arrives on the scene
Pundit The world’s foremost authority
• Written by Elabs
• Simple, uses pure Ruby classes
• Popular and well maintained
• Second most popular Rails authorization gem
Pundit Setup
• Include in Gemfile
• Optionally run generator
• Include in ApplicationControllerclass ApplicationController < ActionController::Base include Pundit protect_from_forgery after_action :verify_authorized, :except => :index after_action :verify_policy_scoped, :only => :index …
rails g pundit:install
gem "pundit"
Policies
• Authorization in Pundit is controlled by Policy classes
• Policies go in app/policies
• Policies are PORC
Policy Example
class PostPolicy < ApplicationPolicy … def update? user.admin? or not post.published? end …
Pundit In Controllers
def update @post = Post.find(params[:id]) authorize @post if @post.update(post_params) redirect_to @post else render :edit end end
Pundit In Views
<% if policy(@post).update? %> <%= link_to "Edit post", edit_post_path(@post) %> <% end %>
Pundit Scopes
class PostPolicy < ApplicationPolicy class Scope < Scope def resolve if user.admin? scope.all else scope.where(:published => true) end end end …
Pundit Scopes In Controllers
def index @posts = policy_scope(Post) end
Pundit Scopes In Views
<% policy_scope(@user.posts).each do |post| %> <p> <% link_to post.title, post_path(post) %> </p> <% end %>
Pundit Strong Parameters 1/2
class PostPolicy < ApplicationPolicy … def permitted_attributes if user.admin? || user.owner_of?(post) [:title, :body, :tag_list] else [:tag_list] end end …
Pundit Strong Parameters 2/2
class PostsController < ApplicationController … private !
def post_params params.require(:post).permit( *policy(@post || Post).permitted_attributes ) end …
Pundit with an API 1/4custom Pundit users
class APIController < ActionController::Base … !
private !
def pundit_user current_device end …
Pundit with an API 2/4custom Pundit users
class APIController < ActionController::Base … Context = Struct.new(:app, :device, :app_instance, :user) … private !
def pundit_user Context.new( current_app, current_device, current_app_instance, current_user ) end …
Pundit with an API 3/4custom Pundit users
AppInstancePolicy < ApplicationPolicy … def update? app_instance == current.app_instance end …
Pundit with an API 4/4
class DeliveriesController < APIController … def cancel @delivery = Delivery.find(params[:id]) authorize @delivery @delivery.cancel !
respond_with @delivery end …
Pundit Is PORC
You can:
• Encapsulate a set of permissions into an included module
• Use alias_method to make permissions behave the same
• Inherit from a base set of permissions
• Use metaprogramming
Questions?