Skip to content

Instantly share code, notes, and snippets.

@jmejia
Last active May 9, 2016 19:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmejia/6a794a885f3b7daa41e9821ca30aaa8b to your computer and use it in GitHub Desktop.
Save jmejia/6a794a885f3b7daa41e9821ca30aaa8b to your computer and use it in GitHub Desktop.
Turing - Multitenancy Authorization Notes

Multitenancy Authorization

Initial Repository

git clone -b multitenancy_authorization https://github.com/turingschool-examples/storedom.git multitenancy_authorization

Final Repository

git checkout —track https://github.com/turingschool-examples/storedom.git multitenancy_authorization_final

Procedure

  • rails g model Role name:string
  • rails g model UserRole user:references role:references
  • Add UserRole relationship in Role
  • Add UserRole relationship in User
  • rake db:migrate
  • Create three roles
    1. platform_admin
    2. store_admin
    3. registered_user
  • Add Permission methods in user model
    1. platform_admin?
    2. store_admin?
    3. registered_user?
  • Create services folder
  • Create Permission service
  • initialize the object with a user
  • implement #allow? method
  • Only allow users to visit the stores controller
  • Add additional permissions
  • Add guest_user and add conditional
  • Abstract permissions into private methods
  • Add Permission methods in ApplicationController
    1. current_permission
    2. authorize!
    3. before_action :authorize!
    4. private method :authorize?
  • Add helpers in ApplicationHelpers
    1. platform_admin?
    2. store_admin?
    3. registered_user?

Workshop

  1. Can you build the permissions for a store admin?
  2. The store admin will have access to the stores, sessions, items, and orders controllers.
  3. However, he won’t have access to the users controller.
  4. Can you create a helper that will hide that functionality from the navbar?

Implementation

app/model/user.rb

class User < ActiveRecord::Base
  has_secure_password

  has_many :user_roles
  has_many :roles, through: :user_roles

  belongs_to :store
  has_many :orders

  def platform_admin?
    roles.exists?(name: "platform_admin")
  end

  def store_admin?
    roles.exists?(name: "store_admin")
  end

  def registered_user?
    roles.exists?(name: “registered_user”)
  end
end

app/model/user_role.rb

class UserRole < ActiveRecord::Base
  belongs_to :user
  belongs_to :role
end

app/model/role.rb

class Role < ActiveRecord::Base
  validates :name, uniqueness: true

  has_many :user_roles
  has_many :users, through: :user_roles
end

app/services/permission.rb

class Permission
  extend Forwardable

  attr_reader :user, :controller, :action

  def_delegators :user, :platform_admin?,
                        :store_admin?,
                        :registered_user?

  def initialize(user)
    @user = user || User.new
  end

  def allow?(controller, action)
    @controller = controller
    @action     = action

    case
    when platform_admin?
      platform_admin_permissions
    when store_admin?
      store_admin_permissions
    when registered_user?
      registered_user_permissions
    else
      guest_user_permissions
    end
  end

  private

  def platform_admin_permissions
    return true if controller == "sessions"
    return true if controller == "items"  && action.in?(%w(index show))
    return true if controller == "stores" && action.in?(%w(index show))
    return true if controller == "orders" && action.in?(%w(index show))
    return true if controller == "users"  && action.in?(%w(index show))
  end

  def store_admin_permissions
    return true if controller == "sessions"
    return true if controller == "items"  && action.in?(%w(index show))
    return true if controller == "stores" && action.in?(%w(index show))
    return true if controller == "orders" && action.in?(%w(index show))
  end

  def registered_user_permissions
    return true if controller == "sessions"
    return true if controller == "items"  && action.in?(%w(index show))
    return true if controller == "stores" && action.in?(%w(index show))
  end

  def guest_user_permissions
    return true if controller == "sessions"
    return true if controller == "items"  && action.in?(%w(index show))
    return true if controller == "stores" && action.in?(%w(index))
  end
end

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.

  protect_from_forgery with: :exception

  before_action :authorize!

  add_flash_types :success,
                  :info,
                  :warning,
                  :danger

  helper_method :current_user

  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end

  def current_permission
    @current_permission ||= Permission.new(current_user)
  end

  def authorize!
    unless authorized?
      redirect_to root_url, danger: "You are not authorized to visit this page"

    end
  end

  def authorized?
    current_permission.allow?(params[:controller], params[:action])
  end
end

app/helpers/application_helper.rb

module ApplicationHelper
  def platform_admin?
    current_user && current_user.platform_admin?
  end

  def store_admin?
    current_user && current_user.store_admin?
  end

  def registered_user?
    current_user && current_user.registered_user?
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment