1

I am learning to use Pundit for authorization. But the way I see it is authorization for resources not pages. I want a user to be redirected to a unauthorized page if he/she is not authorized to visit the page using pundit.

For e.g.

class OnlyAdminCanVisitController < ApplicationController
    before_filter :admin_authenticate

Stops a non-admin role user.

Also, I want to take care of made up scenarios like following(Considering there are 4 roles as Admin,Manager,Employee,Outsider. The design below is obiviously bad)

    class AdminManagerCanVisitController < ApplicationController
        before_filter :admin_or_manager_authenticate

    class AdminEmployeeCanVisitController < ApplicationController
        before_filter :admin_or_employee_authenticate

   class AdminOutsiderCanVisitController < ApplicationController
        before_filter :admin_or_outsider_authenticate

    class AdminManagerEmployeeCanVisitController < ApplicationController
        before_filter :admin_or_manager_employee_authenticate

I have 4 roles and would like to write pundit policies for these controllers which allows any combination of authorizations.

Let me know if pundit is designed to tackle this issue.

Thanks

sethi
  • 1,869
  • 2
  • 17
  • 27

1 Answers1

6

There is not much difference between pages and resources actually. So you can solve your problem by rescuing a denied Authorization from your application_controller.rb :

class ApplicationController < ActionController::Base
  include Pundit

  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  protected

  def admin_authenticate
    authorize current_user, :admin?
  end

  private

  def user_not_authorized(exception)
    # Redirect to whatever page you want if not authorized
  end
end

You then need to define your policy. I generally create an admin? method in application_policy.rb (https://github.com/elabs/pundit#policies) so it is spread on my other policies as well :

class ApplicationPolicy
  def admin?
    # Logic to ensure the user is an admin
  end
end

class UserPolicy < ApplicationPolicy
end

Then in your other controllers, just do as you did :

class OnlyAdminCanVisitController < ApplicationController
  before_action :admin_authenticate
end
lkartono
  • 2,323
  • 4
  • 29
  • 47
  • Thanks..It solves half of my problem. The other half is if I have 4 roles there 4! combination of authorization for example 2 out of 4 are eligible or 3 out of 4 and i cannot have a authenticate function for each of these combinations...let me know if i missed something.. – sethi Jul 08 '15 at 01:26
  • Ok. Could you please update your post with your code related to roles so it's more clear to see the issue. It will depends on how you design the combination user/role Thanks – lkartono Jul 08 '15 at 01:27
  • The policy rule apply for the User object. How did you design your role at the model/database level? – lkartono Jul 08 '15 at 03:39
  • Role is a table and has a many_to_many relationship with the User through a user_roles table – sethi Jul 08 '15 at 04:04
  • Then this is simple. Inside your policy file (`UserPolicy` or `ApplicationPolicy`) create has much rule (like `admin?`) as you need. To stay DRY inside your controller, you could use a `concern` or wrap an utility function to handle roles to check for. My example is based on one role, but the same can be applied to many roles. – lkartono Jul 08 '15 at 04:11
  • Thanks you are right may be i don't have to provide different authenticate function and they can be handled at one place.. – sethi Jul 08 '15 at 05:00