Skip to content
This repository has been archived by the owner on Jun 27, 2020. It is now read-only.

Implementing a Superuser scope with Devise and Warden

dchandekstark edited this page Oct 18, 2014 · 4 revisions

Requirements

  • Users authorized to "act as superuser" should not be signed into :superuser scope by default. Conversely, signing out of :user scope should sign out of :superuser scope (Devise default is to sign out of all scopes when signing out of default scope.)
  • There are no scoped views.
  • Signing in/out of :superuser scope should be a simple toggling.
  • There is no explicit re-authentication because the user is always required to sign into :user scope (via remote authentication)

Devise configuration

# config block in config/initializers/devise.rb

# These settings may be commented out b/c defaults (don't have to uncomment)
config.scoped_views = false
config.default_scope = :user
config.sign_out_all_scopes = true

# This is the important part!
config.warden do |manager|
  # The signed-in superuser has to be serialized/deserialized
  # into/from session to persist across requests.  
  # This example assumes that your regular user model is `User`.
  manager.serialize_into_session(:superuser) { |superuser| superuser.id }
  manager.serialize_from_session(:superuser) { |id| User.find(id) }
end

User Model

You have to implement some mean of determining whether the user logged into default scope (current_user) is authorized to act as superuser. In my case, the user has be a member of a certain group. Another way is to add a boolean column to your User model to authorize superuser ability.

# app/models/user.rb

def authorized_to_act_as_superuser?
  # Your business logic here
end

Route and Controller

I decided to have a special SuperuserController, but you could implement the functionality in ApplicationController.

Route

# config/routes.rb

get 'superuser' => 'superuser#toggle'

Controller

class SuperuserController < ApplicationController

  def toggle
    if acting_as_superuser? 
      # `acting_as_superuser?` will be defined in ApplicationController.
      # As you'll see, we could have simply used `signed_in?(:superuser)`
      # but this method isolat
      sign_out(:superuser)  # Devise method for signing out of a scope
      flash[:success] = "You are no longer acting as Superuser."
    else 
      authorize_to_act_as_superuser!    # See protected method below
      sign_in(:superuser, current_user) # Devise signs current_user into :superuser scope
      flash[:alert] = "<strong>Caution!</strong> You are now acting as Superuser.".html_safe
    end
    redirect_to root_path # Example: redirect to root path after toggling
  end

  protected 

  def authorize_to_act_as_superuser!
    unless current_user.authorized_to_act_as_superuser?
      render nothing: true, status: 403 # Substitute your preferred "unauthorized" handling
    end
  end

end
Clone this wiki locally