Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pundit

 Pundit

Simple Rails authorization

Avatar for Bruce White

Bruce White

July 16, 2014

More Decks by Bruce White

Other Decks in Programming

Transcript

  1. 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)
  2. 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
  3. Pundit The world’s foremost authority • Written by Elabs •

    Simple, uses pure Ruby classes • Popular and well maintained • Second most popular Rails authorization gem
  4. Pundit Setup • Include in Gemfile • Optionally run generator

    • Include in ApplicationController class 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"
  5. Policies • Authorization in Pundit is controlled by Policy classes

    • Policies go in app/policies • Policies are PORC
  6. 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
  7. Pundit In Views <% if policy(@post).update? %> <%= link_to "Edit

    post", edit_post_path(@post) %> <% end %>
  8. Pundit Scopes class PostPolicy < ApplicationPolicy class Scope < Scope

    def resolve if user.admin? scope.all else scope.where(:published => true) end end end …
  9. Pundit Scopes In Views <% policy_scope(@user.posts).each do |post| %> <p>

    <% link_to post.title, post_path(post) %> </p> <% end %>
  10. 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 …
  11. Pundit Strong Parameters 2/2 class PostsController < ApplicationController … private

    ! def post_params params.require(:post).permit( *policy(@post || Post).permitted_attributes ) end …
  12. Pundit with an API 1/4
 custom Pundit users class APIController

    < ActionController::Base … ! private ! def pundit_user current_device end …
  13. Pundit with an API 2/4
 custom 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 …
  14. Pundit with an API 3/4
 custom Pundit users AppInstancePolicy <

    ApplicationPolicy … def update? app_instance == current.app_instance end …
  15. Pundit with an API 4/4 class DeliveriesController < APIController …

    def cancel @delivery = Delivery.find(params[:id]) authorize @delivery @delivery.cancel ! respond_with @delivery end …
  16. 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