Rails3 + OmniAuth で Twitter / Facebook 認証を実現
最近では Web サービスのログインに「Twitterでログイン」、「OpenIDでログイン」というボタンを見かけることが多くなってきた。 はてなの認証APIがリリースされてから5年。 OpenIDやOAuthの普及もあり、外部サイトとの認証連携がようやく当たり前になってきた感がある。
とはいえ、多くのサイトと認証連携しようとすると、個々の認証プロバイダ(Facebook や Twitter や Mixi など)の違いに対応しないといけなくて結構大変。 調べてみたら、Rails3やSinatraの場合はOmniAuthというライブラリが使えそうなので試してみた。
OmniAuthはTwitterやFacebookなどの外部の認証プロバイダと連携するためのライブラリ。 Rackのミドルウェアとして動作するので、RailsやSinatraで使うことができる。 OmniAuthの思想は「authentication is not the same as identity」で、IDと認証を分けて考えている。 つまり、今どきのWebサイトは「○○でログイン」ボタンのように、ユーザが好きな認証方式を選べて当然だよね、ということ。 IDは一つだけど、認証方式は複数。
OmniAuthの役割は、認証プロバイダごとの細かな違いを吸収して、アプリ側からは統一されたインタフェースで呼び出せるようにすること。 認証プロバイダを呼び出す「リクエストフェーズ」と、認証結果を受け取る「コールバックフェーズ」の2つのフェーズから構成される。
Twitterの場合はこうなる。
- /auth/twitter … リクエストフェーズ
- /auth/twitter/callback … コールバックフェーズ
アプリ側ではログインボタンのリンク先を/auth/twitterに設定してTwitterのログイン画面へ飛ばし、認証結果を/auth/twitter/callback に設定したコントローラーで受け取ることができる。
URLのtwitterの部分をfacebookやmixiやflickrに変えることで、他の認証プロバイダを呼び出すことができる。 認証プロバイダとの連携にはOpenIDやOAuthを用いるけど、これらプロトコルの違いはOmniAuthが吸収してくれる。 複数の認証プロバイダからのログインに対応するときに、同じインタフェースで扱えるのはメリットになる。 ちなみに、OmniAuthの内部ではStrategyパターンを使って認証プロバイダごとの細かなロジックを分離している。
認証プロバイダからの認証結果はハッシュで渡される。ハッシュの形式も、OmniAuthが規定している。
- 'provider' … 認証プロバイダの名前
- 'uid' … 認証プロバイダ内で一意となるユーザID
- 'credentials' … OAuthで用いるアクセストークン
- 'user_info' … ユーザの追加情報(ニックネームやメールアドレスなど)
ユーザはproviderとuidのペアで、一意に識別できる。 user_infoに格納されている情報は認証プロバイダごとに異なる。この情報を使うときはコールバック先に登録するコントローラーで処理を分けてあげればいい。(メアドが取得できなかったら登録フォームに飛ばすなど)
サンプルプログラム
本当はOmniAuthのサンプルプログラムを載せようと思ったけど、力尽きたのでここまで。 github上に素晴らしいチュートリアルが公開されているので、これを読むといいと思うよ。
僕はdevise + OmniAuthの組み合わせでEvernote経由のログインを試したけど、最初はdeviseを使わずにOmniAuth単体で使ってみる方が分かりやすいと思う。