When you're building a web application, there's always the question of how to handle the site-wide administration. You probably have a small list of people at your company that should be able to access it. If you're like Intridea, you also use Google Apps to handle e-mail etc. Using OmniAuth it is trivially simple to set up a simple "admin login system" for your Rails 3 app. Here's how to do it.
Step One: OmniAuth Up and Running
First we'll need to include OmniAuth in our
Gemfile. Just add it like
Next, we should configure OmniAuth for our Google Apps login. Note that
you can add this even if you're already using a different Google Apps
strategy for OmniAuth. Create the file
and put this in it:
Rails.application.config.middleware.use OmniAuth::Builder do provider :google_apps, OpenID::Store::Filesystem.new('/tmp'), :domain => 'yourcompany.com', :name => 'admin' end
This makes it so that going to
/auth/admin from your application will
have you authenticate through your company's Google Apps account (and
ONLY your company's accounts will work).
Step Two: Routing
Next let's set up our routes for the admin panel. In this case I'm
supposing that you want to scope everything to an 'admin' subdomain and
also that all of your controllers are module scoped to admin (i.e.
Admin::UsersController), but you could easily use
namespace to make
it a path prefix instead. In
match '/auth/admin/callback', :to => 'sessions#authenticate_admin' constraints :subdomain => 'admin' do scope :module => 'admin', :as => 'admin' do root :to => 'users#index' resources :users # etc. end end
What this has done is created an OmniAuth callback route and a group of
routes that are constrained to the "admin" subdomain and will be
admin_ in the named routes. Now that we've got the
routes set up, let's actually add the controllers!
Step Three: Controllers
First we'll want to make the callback active. Generate a "sessions" controller if you don't already have one, and add this code to it:
class SessionsController < ApplicationController def authenticate_admin auth_hash = request.env['omniauth.auth'] session[:admin_user] = auth_hash['user_info']['email'] if admin? redirect_to '/' else render :text => '401 Unauthorized', :status => 401 end end end
What we do here is take the e-mail that is provided to us by OmniAuth
and store it in the session as the
:admin_user. We then check to
see if that e-mail has admin priveleges (using a method we'll write
in just a moment) and redirect them to the root of the admin section
if so. Next we need to add the
admin? helper to
class ApplicationController def admin? session[:admin_user] && (ENV['ADMINS'] || "").split(',').include?(session[:admin_user]) end helper_method :admin? def admin_required redirect_to '/auth/admin' unless admin? end end
This checks to see if our
:admin_user is in a comma-separated list of
approved administrators set at the environment level (a useful strategy
for Heroku deployments, but you could do lots of things here such as
load a list from YAML etc.). We've also written a method that will be
used as a
before_filter to require admin login.
Next up let's actually make our protected resources! If you don't already have it, generate a user admin controller:
rails g controller admin/users
Next up let's just add a simple action to make sure it works:
module Admin class UsersController < ApplicationController before_filter :admin_required def index render :text => 'Hello from the admin panel!' end end end
With that, you're done! When you go to
admin.yourapp.com you should be
redirected to log in using Google Apps. Once you've done that, if your
name is on the comma-separated list you will be authorized to access the
protected controller. This is a simple method that is independent of
database storage so can be very useful in just about any application.
When OmniAuth makes it so easy, there's no reason not to make your
administrative login as smooth and painless as possible!