Shared Auth for Rack Apps September 26th, 2011
Being able to mount rack apps inside each other is awesome.
Resque::Server for monitoring job processing and
that means I wont have to write an interface for it myself.
/admin/resque is going to be what I want with
practically no work on my part. But since I'm using these
for real in the admin area of
Bugrocket – there's a
problem with just mounting apps under
parts that I wrote myself use my authentication
layer — and they make sure you're actually an administrator!
I could wrap
Resque::Server in some other rack app I write,
which would duplicate the logic and require the user to
login again. Or maybe use HTTP basic auth... not much better.
This is written from the perspective of mounting
inside a Rails 3.X app. Warden is pretty flexible though,
so you could conceivably do this with any rack app
as the parent.
Mount your micro-app wherever as above.
At the time of writing
rails_wardenfrom rubygems was giving me strange errors I didn't have time to look into. If you have trouble just use the git repo as the source:
:git => 'git://github.com/hassox/rails_warden.git'
config/initializers/warden.rb is where we'll make this all happen.
First we tell Warden the strategies we plan to use.
an arbitary name – it's what I'm going to be authenticating.
Then you can specify whichever controller you want the user to be
redirected to when they need to login. In my case I have
a sessions controller in the
Admin namespace, pretty typical.
Next you need to define some hooks Warden will use to get and persist the current user to the session:
Again pretty typical.
Now we get into the meat. We need to define what the
we mentioned earlier actually does to authenticate a user.
authenticate! method is the logic that used to be part of
a helper in my actual admin controllers. We're moving it here so it
can be shared.
Wiring It Up
So at this point we can already go ahead and use this code for authenticating in the parent app, replacing all the auth code we used to have written directly with the new Warden-backed implementation.
You probably have a helper somewhere, something like this:
Well now we can just change it to:
Similarly, we can just call the same
Admin::SessionsController#create method and no longer
need to write the authentication logic in our controller
– everything is handled by Warden.
So assuming all of that is working you have successfully replaced your inline authentication, but nothing has really changed. Users still wont be asked to login when visiting mounted apps.
But this last step is super easy. We just define an authentication middleware:
This looks a bit fiddly but there's nothing to it. Basically
we just transplant our Rails app's session configuration
rack.session.options, because that's where rack apps are
expecting to see session info. Warden conveniently places
a lazy-loaded instance into
env for us, we call it
just like we are in our regular admin controllers, and
we receive many fresh sandwiches.
The last bit is just telling our mounted app(s) to use the new middleware.
Take a look at an example app that demonstrates all of this stuff.
Some social stuff: