Google+ APIを試してみた(OAuth 2.0編)

前回の続きです。
今回は、OAuth 2.0のアクセストークンを使って公開ストリームを取得するアプリをRailsで作ってみました。
ソースコードGitHubにアップしています。

OAuth 2.0の仕様はこちら。

OAuth - Google+ Platform — Google Developers

OAuth 2.0を利用するには、事前にGoogle APIコンソールにてクライアントID、クライアントシークレット、リダイレクトURIなどを登録しておく必要があります(この辺りを参考)。
登録するリダイレクトURIlocalhostでもOKです。
ただし、ここで登録したURLと実際にアプリでリダイレクトさせるURIが一致しないと、認証APIを実行したときにエラーになるので注意が必要です。
今回はリダイレクトURIを下記のように登録してみました。

localhost:3000/activities/oauth2callback
ビュー

app/views/activities/index.html.erb

<h1>Listing activities</h1>

<table>
  <tr>
    <th>Title</th>
    <th>Published</th>
    <th>URL</th>
  </tr>

<% if @activities.present? && @activities["items"].present? %>
  <% @activities["items"].each do |activity| %>
    <tr>
      <td><%= activity["title"] %></td>
      <td><%= activity["published"] %></td>
      <td><%= activity["url"] %></td>
    </tr>
  <% end %>
<% end %>
</table>

なんの変哲もないビューです。

コントローラ

app/controllers/activities_controller.rb

def index
  # アクセストークン未取得または有効期限切れの場合はOAuth 2.0で認証する
  redirect_to "https://accounts.google.com/o/oauth2/auth?"\
    "client_id=#{CLIENT_ID}&"\
    "redirect_uri=#{REDIRECT_URI}&"\
    "scope=https://www.googleapis.com/auth/plus.me&"\
    "response_type=code" and return if cookies[:access_token].blank?

  # 公開ストリームを取得する
  uri = URI.parse("https://www.googleapis.com/plus/v1/people/me/activities/public?"\
    "access_token=#{cookies[:access_token]}")
  https = Net::HTTP.new(uri.host, 443)
  https.use_ssl = true
  https.verify_mode = OpenSSL::SSL::VERIFY_NONE
  response = https.start do |https|
    request = Net::HTTP::Get.new(uri.path << '?' << uri.query)
    https.request(request)
  end

  @activities = ActiveSupport::JSON.decode(response.body)
end

認証済みの場合は公開ストリーム取得APIを実行しますが、未認証の場合はアクセス許可画面にリダイレクトさせます(認証情報をクッキーに保存しています)。
CLIENT_ID、REDIRECT_URIは、事前登録したクライアントIDとリダイレクトURIです。
注意点は、サーバ側の実装なのでresponse_typeをcodeにすること。

リダイレクトURIのアクションの実装です。

def oauth2callback
  # アクセスを許可しなかった場合はトップ画面にリダイレクトする
  redirect_to url_for(:controller => "tops", :action => "index") and return if params["code"].nil?

  # 認可コードをアクセストークンおよびリフレッシュトークンと交換する
  uri = URI.parse("https://accounts.google.com/o/oauth2/token")
  https = Net::HTTP.new(uri.host, 443)
  https.use_ssl = true
  https.verify_mode = OpenSSL::SSL::VERIFY_NONE
  response = https.start do |https|
    request = Net::HTTP::Post.new(uri.path)
    request.set_form_data({
      :code          => params[:code],
      :client_id     => CLIENT_ID,
      :client_secret => CLIENT_SECRET,
      :redirect_uri  => REDIRECT_URI,
      :grant_type    => "authorization_code"
    }, "&")
    https.request(request)
  end

  response_hash = ActiveSupport::JSON.decode(response.body)
  cookies[:access_token] = {
    :value => response_hash["access_token"],
    :expires => response_hash["expires_in"].seconds.from_now
  }
  @activity = Activity.new(:access_token => response_hash["access_token"])
  @activity.save

  redirect_to url_for(:activities)
end

アクセス許可画面にてアクセスを許可した場合は認可コードがリクエストパラメータとして渡されるので、これをアクセストークンおよびリフレッシュトークンと交換します。
取得したアクセストークンはクッキーなりDBなりに保存しておきましょう。

動作確認

http://localhost:3000/activitiesにアクセスしてみます。
すると、まだ認証していないのでアクセス許可画面にリダイレクトされます(Twitterなどでもおなじみの画面です)。

ここで「アクセスを許可」を選択すると、まずhttp://localhost:3000/activities/oauth2callbackにリダイレクトされて認証したあと、http://localhost:3000/activitiesにリダイレクトされます。
今度は認証済みなので、公開ストリームを取得できるはず。

おー、できました。
Google+を使っていないことがバレバレの公開ストリームですが、気にしないでください。

なお、アクセストークンの有効期限は1時間なので、1時間以内であれば再認証は不要です。