PicasaAPIを使ってOAuth2.0のフロー(Authorization Code)を確認した。
OAuth、書籍やネット上の記事などから大まかに仕組みは理解していたのですが、具体的にリクエスト/レスポンスをどう送り合ってやりとりを行っているのかがよくわかっていませんでした。 OAuthの一連の流れを理解するために、今回は実際にOAuth2.0から認可してもらう流れをライブラリを使わずに実装していきたいと思います。
OAuth1.0はsignetureを作るのが少しメンドクサそうだったので、今回はOAuth2.0だけやります。
参考
OAuth2.0について
Google Photosへのアップロードについて
やること・ゴール
- Rubyで簡易的な実装で流れを掴んで行きたいと思います。
- Google PhotosにOAuth2.0で画像をアップロードできるよう認可してもらい、実際に画像をアップロードできるようにするところまでやっていきたいと思います。 (自宅のPCはUbuntuを使っているのですが、Google PhotosのクライアントはWindowsとMacしかないので、今後自作でちゃんとしたクライアント作っていくために、今回Google Photosへアップロードする流れを確認しました。)
- Google Photosは統合前のサービスPicasa、このAPIが使えます。(Google Photosというのは残念ながらないようです。)
OAuth2.0の認可フロー(Grant Type)
OAuth2.0の認可フローには4種類あります。 各フローにyoutubeに解説の動画があるので、リンクを貼っておきます。
Authorization Code 動画:https://www.youtube.com/watch?v=j0pIlZdD7-A&feature=youtu.be
- サーバサイドで多くの処理を行うウェブアプリケーション向けのフロー
Implicit 動画:https://www.youtube.com/watch?v=fF1mJB64xAg
- スマホアプリやJSを用いたクライアント再度で処理の多くを行うアプリケーション向けのフロー
Resource owner password credentials 動画:https://www.youtube.com/watch?v=qS0YY9Fo04Q
- サーバサイドを利用しないアプリケーション向けのフロー
Client Credentials 動画:https://www.youtube.com/watch?v=LLIMOYk5Syc
- ユーザ単位での認可を行わないアプリケーション向けのフロー
今回は、今後WEBアプリケーションで使っていけるよう、上記フローのうちAuthorization Codeで実装します。
googleからクライアント ID、クライアントシークレットをもらう
Google APIs Consoleへログインし、クライアント ID、クライアント シークレットをもらいます。 手順は検索すると多くの記事がでてくるので割愛します。
今回はAuthorization Codeで実装を行うので、アプリケーションの種類
はウェブ アプリケーション
を選択しました。
承認済みのリダイレクト URI
は、ユーザが認可のためGoogleにログイン後にリダイレクトされるURIなのですが、ここにクエリとしてアクセストークンがくっついてきます。
その他
にすると、リダイレクトされず、トークンが画面に表示されるようになります。
(Android、Chromeアプリ、iOS、PlayStation4にするとどういう動きになるかがわかりませんが、気になる方は調べてみると良いでしょう。)
認可コード(Authorization Code)をもらう
以下のコードで、認可コード(Authorization Code)をもらうためのログイン画面を表示します。 ここでは、uriの組み立てだけなのですが、hashでいい感じにクエリ付のuriを生成してくれるので、net/httpを使って実装しています。 (リクエストは送っていません。)
パラメータの仕様は以下です。 https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
state
も指定できるので、WEBアプリケーションを実装するときにはつけておいた方が良いでしょう。
# -*- coding: utf-8 -*- require 'uri' require 'net/http' client_id = { クライアントID } redirect_uri = { リダイレクトURI } # Google APIs Consoleで登録したリダイレクトURIを入力します。異なる場合を入れた場合はエラーになります。 scope = 'https://picasaweb.google.com/data/' # Google Photosはpicasaのapiを利用しているので、次のURLを入れます。 uri = URI('https://accounts.google.com/o/oauth2/v2/auth') params = { response_type: 'code', client_id: client_id, redirect_uri: redirect_uri, scope: scope } uri.query = URI.encode_www_form(params) puts uri.to_s
ログインが完了したら、redirect_uriで指定したuriにリダイレクトされます。 その際に、クエリにcode={Authorization Code}がついてくるので、それをコピーしておきます。 WEBアプリケーションを実装する場合は、コールバック用のuriを用意しておき、Authorization Codeを取得できるようにしておくと良さそうです。
アクセストークンを取得する
以下のリクエストで、アクセストークンを取得します。 WEBアプリケーションを選択した場合は、有効期限はないため、リフレッシュトークンは発行されません。
# -*- coding: utf-8 -*- require 'uri' require 'net/http' require 'openssl' authorization_code = { 先ほど取得したauthorization_code } client_id = { クライアントID } client_secret = { クライアントシークレット } redirect_uri = { リダイレクトURI } uri = URI.parse('https://www.googleapis.com/oauth2/v4/token') https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true request = Net::HTTP::Post.new(uri.request_uri) request.set_form_data({ code: authorization_code, client_id: client_id, client_secret: client_secret, redirect_uri: redirect_uri, grant_type: 'authorization_code' }) response = https.request(request) puts response.code puts response.body
アクセストークンを使って、画像アップロード
以下のコードで画像をアップロードしてみます。
# -*- coding: utf-8 -*- require 'uri' require 'net/http' require 'openssl' user_id = { アップロードするユーザのid } access_token = { アクセストークン } upload_file = 'sample.jpg' uri = URI.parse("https://picasaweb.google.com/data/feed/api/user/#{user_id}/?access_token=#{access_token}") https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true request_header = { 'Content-Type': "image/jpeg", 'Content-Length': File.size(upload_file).to_s, 'Slug': upload_file } request = Net::HTTP::Post.new(uri.request_uri, request_header) request.body = File.read(upload_file) response = https.request(request) puts response.code puts response.body
アップロードされた画像を確認する
Google Photesアクセスし、画像がアップロードされていることを確認します。
OAuth2.0でGoogle PhotosへのアクセスをGoogleに認可してもらい、実際にアップロードできるところまで確認しました。 Authorization Code以外の認可フローについてはまた別の機会にやろうと思います。