pundit

21
Pundit simple Rails authorization Ruby::AZ - July 15, 2014 Bruce White Software Ops developer [email protected]

Upload: bruce-white

Post on 14-Jun-2015

814 views

Category:

Technology


1 download

DESCRIPTION

Pundit Simple Rails Authorization

TRANSCRIPT

Page 1: Pundit

Pundit simple Rails authorization

Ruby::AZ - July 15, 2014

Bruce White Software Ops developer [email protected]

Page 2: Pundit

We Build Mobile App Systems

Page 3: Pundit

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)

Page 4: Pundit

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

Page 5: Pundit

Pundit The world’s foremost authority

• Written by Elabs

• Simple, uses pure Ruby classes

• Popular and well maintained

• Second most popular Rails authorization gem

Page 6: Pundit

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"

Page 7: Pundit

Policies

• Authorization in Pundit is controlled by Policy classes

• Policies go in app/policies

• Policies are PORC

Page 8: Pundit

Policy Example

class PostPolicy < ApplicationPolicy … def update? user.admin? or not post.published? end …

Page 9: Pundit

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

Page 10: Pundit

Pundit In Views

<% if policy(@post).update? %> <%= link_to "Edit post", edit_post_path(@post) %> <% end %>

Page 11: Pundit

Pundit Scopes

class PostPolicy < ApplicationPolicy class Scope < Scope def resolve if user.admin? scope.all else scope.where(:published => true) end end end …

Page 12: Pundit

Pundit Scopes In Controllers

def index @posts = policy_scope(Post) end

Page 13: Pundit

Pundit Scopes In Views

<% policy_scope(@user.posts).each do |post| %> <p> <% link_to post.title, post_path(post) %> </p> <% end %>

Page 14: Pundit

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 …

Page 15: Pundit

Pundit Strong Parameters 2/2

class PostsController < ApplicationController … private !

def post_params params.require(:post).permit( *policy(@post || Post).permitted_attributes ) end …

Page 16: Pundit

Pundit with an API 1/4custom Pundit users

class APIController < ActionController::Base … !

private !

def pundit_user current_device end …

Page 17: Pundit

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 …

Page 18: Pundit

Pundit with an API 3/4custom Pundit users

AppInstancePolicy < ApplicationPolicy … def update? app_instance == current.app_instance end …

Page 19: Pundit

Pundit with an API 4/4

class DeliveriesController < APIController … def cancel @delivery = Delivery.find(params[:id]) authorize @delivery @delivery.cancel !

respond_with @delivery end …

Page 20: Pundit

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

Page 21: Pundit

Questions?