GoogleのOAuthを試してみた

 GoogleやTwitterなどで公開されているWeb APIを、ユーザのパスワードを預かることなく呼び出すことのできるOAuthというのを試してみました。

当初はOAuthの仕様を見ながらフルスクラッチで作ろうとしたのですが、よく考えたら私は英語が読めないのでした。1から作るのは諦めて公開されているrubyのライブラリを使うことにしました。

 

まずはサイトの登録

 

WebアプリケーションからGoogleのOAuth認証を使う場合、サイトの登録をしないといけません。登録は以下のURLから行います。

https://www.google.com/accounts/ManageDomains

 

この登録はドメイン単位で行われるので自分のドメインを持っていないと話にならないようです。なんてこったい。

しかし我々にはGoogle App Engineがついていました。ダメもとでsyttru.appspot.comを登録してみたら無事に登録完了。所有権を確認するためのメタタグをトップページに埋め込んで登録と確認が無事に完了しました。

サイトを登録するとOAuthで使うためのキーと秘密文字列が発行されます。これがないとOAuthリクエストができないので大事にメモしておきます。

 

コンシューマの作成

 

ここからプログラムに入ります。

全体のコードは最後の方に貼っておきますので気の短い方はそちらを御覧下さい。

まずはコンシューマの生成。

  consumer = OAuth::Consumer.new key, secret, {
    :signature_method   => 'HMAC-SHA1',
    :site               => 'https://www.google.com',
    :request_token_path => '/accounts/OAuthGetRequestToken',
    :authorize_path     => '/accounts/OAuthAuthorizeToken',
    :access_token_path  => '/accounts/OAuthGetAccessToken',
  }

 OAuth::Consumerクラスのコンストラクタに発行されたキーと秘密文字列を渡します。三つ目の引数は各種オプションです。

signarute_method

コンシューマからGoogleへのリクエストに署名をするための方式を指定します。OAuthの仕様では「PLAINTEXT」「HMAC-SHA1」「RSA-SHA1」の三つが定義されていますが、GoogleはPLAINTEXTをサポートしていません。今回はHMAC-SHA1方式で署名します。

このリクエストの署名をするときにさっきの秘密文字列を使います。リクエストメソッド・URL・リクエストパラメータの3つのデータを、Googleとコンシューマの間だけで共有している秘密文字列を使って変換して署名することによって、他のコンシューマがリクエストを偽造することを防止できるわけです。

この辺を自前で実装しようとして苦労しました。まず英語が読めないので仕様がよくわからない上に署名というものがなんだかよくわかっていなかったので実装できるわけがなかったです。でも署名について理解が深まったからこれでいいのだ。

site

request_token_path

authorize_path

access_token_path

サービスプロバイダのドメインと各種URLです。

コンシューマがOAuthを通して認証をクリアするまで、Googleに対して全部で三回リクエストを発行しないといけません。これらリクエストのURLを設定しています。

 

リクエストトークンの取得

  

  request_token = consumer.get_request_token(
    {
      :oauth_callback => "http://syttru.appspot.com/"
    }, 
    :scope => 'https://www.google.com/analytics/feeds/'
  )

 コンシューマから以下のURLにリクエストを送ってリクエストトークンを取得します。

https://www.google.com/accounts/OAuthGetRequestToken

ここで取得したトークンはコンシューマが一方的に取得したもので、まだユーザーの認証がされていません。このリクエストをユーザーに認証してもらう必要があります。

oauth_callback

ユーザーによる認証はGoogleとユーザーの間で行われます。認証が終わった後でGoogleがリクエストをリダイレクトする先のURLをここで指定します。

scope

2つめの引数でリクエストに追加するパラメータを指定しています。scopeパラメータはコンシューマにアクセス許可を与えるGoogleのサービスを指定します。使用できるscopeの一覧は以下のページにまとめられています。

http://code.google.com/intl/ja/apis/gdata/faq.html#AuthScopes

 

ユーザーによる認証とアクセス許可

 

  puts request_token.authorize_url

 

https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=********************************************

ユーザーによる認証を行うために認証用のURLをユーザーに示す必要があります。実際のWebアプリケーションでは認証用のURLにリダイレクトさせて、認証をしてもらうことになります。

ブラウザで上のURLを開くとGoogleのアカウント画面が開き、コンシューマがGoogleのサービスにアクセスすることを許可するか尋ねられます。

ユーザーが許可するとGoogleは上で指定したoauth_callbackのURLにリクエストをリダイレクトし、その際にverifierという秘密の文字列を発行してリクエストパラメータに付与します。

 

アクセストークンの取得

 

上のやりとりでユーザーがコンシューマに対してGoogleのサービスにアクセスする許可を与えました。その許可を証明するverifierがコンシューマにリクエストパラメータとして渡されるので、コンシューマはこれを使ってGoogleからアクセストークンを取得します。

 

  access_token = request_token.get_access_token(
    :oauth_verifier => oauth_verifier
  )

以降、コンシューマはこのアクセストークンを使うことで、Googleのサービスにユーザーのアカウントでアクセスできるようになります。

 

サービスにアクセス

 

サービスにアクセスするには上で取得したアクセストークンを使います。

resp = access_token.get('/analytics/feeds/accounts/default')

上の例を実行すると、ユーザーのアカウントでGoogle Analytics Data Export APIにアクセスしてユーザのデータを取得したりすることができます。

 

思ったこと

 

まとめるとこんな感じ。

  1. コンシューマ --[リクエストトークン取得]--> サービスプロバイダ
  2. コンシューマ <--[リクエストトークン]-- サービスプロバイダ
  3. コンシューマ --[リクエストトークン]--> ユーザ
  4. ユーザ --[リクエストトークン & 認証とアクセス許可]--> サービスプロバイダ
  5. ユーザ <--[認証済リクエストトークン]-- サービスプロバイダ
  6. コンシューマ <--[認証済リクエストトークン]-- ユーザ
  7. コンシューマ --[認証済リクエストトークン]--> サービスプロバイダ
  8. コンシューマ <--[アクセストークン]-- サービスプロバイダ
  9. コンシューマ --[アクセストークン & API利用]--> サービスプロバイダ

ユーザとコンシューマとサービスプロバイダが入り乱れて三人でくんずほぐれつする様子はOpenIDと似ています。

GoogleやYahoo、Twitterといった大きなサービスがOAuthを提供しているのでいろいろと試してみようと思います。

 

ソースコード

 

 

require 'rubygems'
require 'oauth'
require 'oauth/consumer'

key = '******************'
secret = '************************'

begin
  # keyとsecretを指定してコンシューマを生成
  consumer = OAuth::Consumer.new key, secret, {
    :signature_method   => 'HMAC-SHA1',
    :site               => 'https://www.google.com',
    :request_token_path => '/accounts/OAuthGetRequestToken',
    :authorize_path     => '/accounts/OAuthAuthorizeToken',
    :access_token_path  => '/accounts/OAuthGetAccessToken',
  }

  # リクエストトークンを取得
  request_token = consumer.get_request_token(
    {
      :oauth_callback => "http://syttru.appspot.com/"
    }, 
    :scope => 'https://www.google.com/analytics/feeds/'
  )

  # サービスプロバイダの認証画面URL
  puts request_token.authorize_url

  print "Enter oauth_verifier:"
  oauth_verifier = STDIN.gets.gsub(/\n/, "")

  # ユーザがアクセスを許可したことを証明するverifierを持ってアクセストークンをもらいに行く
  access_token = request_token.get_access_token(
    :oauth_verifier => oauth_verifier
  )

  # サービスにアクセス
  resp = access_token.get('/analytics/feeds/accounts/default')
  puts resp
rescue OAuth::Unauthorized => error
  puts error.to_s
  puts error.request
end

 

 

 

Trackback URL for this post:

http://blog.smartnetwork.co.jp/staff/trackback/46
from modkaの日記 on 金, 2011/09/30 - 15:52
はー。久しぶりに書くな。 Google カレンダー APIからデータを取得する機会があったので、忘れないようにメモ。 ClientLoginで簡単にやろうかと思ったけど結局OAuthを使った。 AuthSubはドキュ...

レビトラ 販売

過去数年間では、薬剤の新しいクラスは、ED(勃起不全)の男性を助けるために開発されている。バイアグラが発売されると、これらのいわゆる"偏微分方程式-5阻害剤"の第一号だった。レビトラは、米国で利用できるように、2番目、3番目、シアリスは、すぐに来ている。 (すべての3つのヨーロッパで現在入手可能です。)- レビトラ 販売