User Authentication and Authorization
In my app I’m using Guardian for for authentication and session management. Guardian has a lot of interesting functionality but at the moment I’m using it for simple password based authentication of users. And, for authorization I’m using the Canary library.
If you aren’t familiar with these two terms I’ll explain.
I use authentication to manage logins and sessions. The user authenicates him or herself by providing a user name and password. Once authenticated a session is created on the user’s behalf.
Once logged in the user has a certain set of privileges. For example, a user may be allowed to modify certain resources that he or she owns. But that same user may not be allowed to modify resources that belong to other users. Canary checks to see if a user is authorized to cary out the actions that he or she requests.
My Guardian configuration is pretty simple. I wrote up these pipelines for my router for Guardian:
Then I have created scopes that either support a logged in user or require a logged in user. For example:
This scope user the
:browser_session pipeine to load a session if one exists.
But it doesn’t require a session. This way both logged in users or guest users
can browse the home page and search.
But the resouces in this scope require a user to be logged in:
Here, I add the
:require_login pipeline which uses Guardian’s
plug to require a session. Errors are passed off to my
MyApp.GuardianErrorHandler module which is responsible for redirecting guest
/login. This is a simple module that looks like this:
My Canary Setup
I use canary in my controllers to check if a user has authorization to view or modify a given resource.
For example, above we saw routes that edit rentals and create images for those rentals. And that these routes require a logged in user. Well, we need more than just a logged in user. The user needs to own those resources.
Here’s an example of how I use Canary to authorize for Images:
:authorize_resource plug checks if the current user is allowed to act on the a
Rental. This of course depends on a
can? function. Here’s part of the
can? function I’ve written:
Here I decide if the user is authorized depending on the action.
Using Canary with Guardian
All of the above seems pretty great, but it doesn’t work!
One of the problems I had making Guardian and Canary play well together was that
Canary depends on being able to find the current user in the connection.
Guardian maintains the current user and it can be accessed by calling
Guardian.Plug.current_resource(conn). But, Canary expects the current user in
:current_user assign in the conn.
To make this work I wrote up another small plug:
This plug simply queries the current user from Guardian and put’s it into the
:current_user assign in the
conn. This copies the data from Guardian’s location to the location Canary expects.
I add this plug to my
With this plug Canary can access
:current_user as an assign and all is well. I
also use the
:current_user assign in my own code. My controllers don’t need to
know about Guardian.
This post focused on how I use Guardian and Canary together to authenticate and authorize in my app. I covered all of my Guardian usage and what I had to do in order to use the two libraries together. But, there’s a bit more to my Canary usage that I hope to write about next week.