Heroku + Sinatra + OAuth2.0 + Google API Client で Googleアカウントでログイン
前回のTwitterアカウントでログインに引き続き、今回は、Googleのアカウントを使ってGoogleのサービスにログイン済みの場合にはIDとPasswordを入力させることなくログインをさせる、OAuth2.0を使ったGoogleアカウントでログインの実装例の紹介です。
今回もまたHeroku + Sinatraを使っています。Google APIのOAuth2.0の実装はまだexperimentalの段階ですが、今後主流となっていくと思いますので認証するサンプルを作りました。GooleのOAuthのAPIはTwitterのように、読みと書きの2つしか用意されてないとうことはなく、細かくスコープが分けられていて非常に良い認証、権限の仕組みかなと思います。
実際に動くサンプルはこちら
http://google-login.heroku.com/
です。
基本的にリソースは、
http://code.google.com/intl/ja/apis/accounts/docs/OAuth2.html
を参考にしています。動きを見てみてOAuth2.0とはなんぞやと思う人はしっかり読んでみてください。
やり方は、結構簡単
- APIs Console
https://code.google.com/apis/console
にアクセスして、自分の好きなGoogleアカウントでGoogleのAPI Accessをさせるアプリケーションを作成します。Create OAuth2.0 API ProjectでWebserver Apllicationを登録します。
そして、
- Client ID:
- Client secret:
を取得。コールバックのURLはドメイン名があっていなくてはいけないので、ローカルでsinatraを動かしたりして検証するのであれば、localhost:4567のドメインのClient IDとClient secretを用意しましょう。もし、ログイン情報の他、他のスコープのAPIも利用するのであれば、All Servicesのところから使うAPIを設定することができます。
あとは以下のソースの、oauth_client_idとoauth_client_secretを書き換えるだけで利用できます。ちなみに利用しているGoogle API clientのgemは本来は、公開されているAPIを探してきて、それを利用するためのツールでもあります。ですが、ここではOAuth2.0のトークンとユーザー情報とメールアドレスのスコープを設定して情報を取得するためだけに利用しています。
ソースコードは以下の通り。GitHubからもダウンロード可能。
google_login.rb
require 'rubygems' require 'sinatra' require 'google/api_client' require 'httpadapter/adapters/net_http' require 'pp' require 'yaml' use Rack::Session::Pool, :expire_after => 86400 # 1 day # Configuration # See README for getting API id and secret if (ARGV.size < 2) set :oauth_client_id, 'oauth_client_id' set :oauth_client_secret, 'oauth_client_secret' if (settings.oauth_client_id == 'oauth_client_id') puts 'See README for getting API id and secret. Server terminated.' exit(0) end else set :oauth_client_id, ARGV[0] set :oauth_client_secret, ARGV[1] end # Configuration that you probably don't have to change set :oauth_scopes, 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email' class TokenPair @refresh_token @access_token @expires_in @issued_at def update_token!(object) @refresh_token = object.refresh_token @access_token = object.access_token @expires_in = object.expires_in @issued_at = object.issued_at end def to_hash return { :refresh_token => @refresh_token, :access_token => @access_token, :expires_in => @expires_in, :issued_at => Time.at(@issued_at) } end end # At the beginning of any request, make sure the OAuth token is available. # If it's not available, kick off the OAuth 2 flow to authorize. before do @client = Google::APIClient.new( :authorization => :oauth_2, :host => 'www.googleapis.com', :http_adapter => HTTPAdapter::NetHTTPAdapter.new ) @client.authorization.client_id = settings.oauth_client_id @client.authorization.client_secret = settings.oauth_client_secret @client.authorization.scope = settings.oauth_scopes @client.authorization.redirect_uri = to('/oauth2callback') @client.authorization.code = params[:code] if params[:code] if session[:token] # Load the access token here if it's available @client.authorization.update_token!(session[:token].to_hash) end # @service = @client.discovered_api('userinfo', 'v1') unless @client.authorization.access_token || request.path_info =~ /^\/oauth2/ redirect to('/oauth2authorize') end end # Part of the OAuth flow get '/oauth2authorize' do <<OUT <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Google Ruby API Login Sample</title> </head> <body> <header><h1>Google Ruby API Login Sample(profile and mailadress)</h1></header> <div class="box"> <a class='login' href='#{@client.authorization.authorization_uri.to_s}'>Login and get your profile!</a> </div> </body> </html> OUT end # Part of the OAuth flow get '/oauth2callback' do @client.authorization.fetch_access_token! unless session[:token] token_pair = TokenPair.new token_pair.update_token!(@client.authorization) # Persist the token here session[:token] = token_pair end redirect to('/') end # The method you're probably actually interested in. This one lists a page of your # most recent activities get '/' do result = @client.execute(:uri => 'https://www.googleapis.com/oauth2/v1/userinfo') response = result.response json = response.to_s ary = YAML.load(json) profile_json = ary[2][0] profile = YAML.load(profile_json) <<OUT <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Google Ruby API Login Sample</title> </head> <body> <header><h1>Google Ruby API Login Sample(profile and mailadress)</h1></header> <div class="box"> <a class='logout' href='/logout'>Logout</a> <h5> id : #{profile['id']} </h5> <h5> email : #{profile['email']} </h5> <h5> verified_email : #{profile['verified_email']} </h5> <h5> name : #{profile['name']} </h5> <h5> given_name : #{profile['given_name']} </h5> <h5> family_name : #{profile['family_name']} </h5> <h5> picture : #{profile['picture']} </h5> <h5> gender : #{profile['gender']} </h5> <h5> locale : #{profile['locale']} </h5> </div> </body> </html> OUT end get '/logout' do session[:token] = nil redirect to('/') end
ローカルで動かすだけなら必要なgemを用意して、以上のファイルだけで
ruby google_login.rb
でサーバーを起動して、http://localhost:4567にアクセスして動かすことができます。
流れとしてはTwitterの時と同じですが、ルートにアクセスの後、セッションにトークンが残っているか見て、あればクライアント取得、無ければアクセストークンの取得をさせるURLを表示。リンクを押してもらって取得、認証の後は、ユーザー情報で取得できるプロフィールとメールアドレスをページに表示します。ログアウトはセッション情報を空にするだけです。
一応、Herokuにpushする時に必要となる以下のconfig.ruとGemfileも用意しておきました。Gemfileは、ローカル環境でgem install bundlerがしてあれば、bundle installコマンドで必要なgemライブラリのインストールもしてくれます。便利。
config.ru
require './google_login' run Sinatra::Application
Gemfile
# Detail http://devcenter.heroku.com/articles/bundler source 'http://rubygems.org' gem 'sinatra' , '1.3.1' gem 'google-api-client' , '0.3.0'
基本的には以上3ファイルを同一フォルダに置いて、ローカルのgitリポジトリにcommitした後。
heroku create git push heroku master
でHeroku上でも利用可能になると思います。その際にGoogleのClient IDのコールバックURLのドメインをHerokuのものに変更しておくことを忘れないようにしておいてください。
ちなみにRubyのGoogle API ClientのOAuth2.0で利用できるAPIの数々が、
http://code.google.com/p/google-api-ruby-client/wiki/SupportedAPIs
にまとめられています。最近の流行りはやっぱりGoogle+ APIを使ったソーシャルアプリ開発なんでしょうかね。あまり自分はGoogle+活用できていませんが、チャンスがあればAPI使ってみたいです。ただ、制限がCourtesy limit: 1,000 queries/dayとなっていて、いろいろやるにはGoogleさんに相談してお金を払う必要がありそうですが...。悩ましい。
今回使ったユーザー情報取得APIの情報はこちら
- Using OAuth 2.0 for Login (Experimental)
http://code.google.com/intl/ja/apis/accounts/docs/OAuth2Login.html
あと、なにげに自分のGoogleアカウントで認証したアプリケーションのアクセス許可の取り消しですが、Googleにログインしたときにでる、右上の自分の名前のところから、 アカウント設定 > アカウントの概要 > アプリケーションとサイトを認証する > 編集 から選択することができます。実にわかりにくいです...。知らずに認証してしまったアプリ等があったら、認証を取り消しておくのが無難です。
何か、指摘等あればコメントで教えてもらえると助かります。