Closed15

Google::Apis::DriveV3 (Ruby) で Google Drive を操作する

snakasnaka

REST client の使い方を見ていく

googleapis/google-api-ruby-client: REST client for Google APIs

実際の Gem はサービス毎に分かれているっぽい

The client gems are named according to the pattern google-apis-<servicename>_<serviceversion>. For example, the client for the Google Drive V3 API is google-apis-drive_v3.

Google Drive の場合は google-apis-drive_v3 という Gem を利用する。

ユーザガイドを読む

google-api-ruby-client/usage-guide.md at main · googleapis/google-api-ruby-client

snakasnaka

認証について理解する

認証の概要  |  Google Cloud

プリンシパル

  • ユーザーアカウント
    • 人間のユーザに代わってリソースにアクセスする場合
  • サービスアカウント
    • 人間のユーザ以外(アプリケーション自体)がリソースにアクセスする場合

認証ストラテジ

種類

  • API キー
    • 一般公開データへの匿名アクセスする
  • OAuth 2.0 クライアント
    • エンドユーザに代わって限定公開データにアクセスする
  • 環境提供のサービスアカウント
    • Google Cloud 環境内で、サービスアカウントに代わって限定公開データにアクセスする
  • サービスカウントキー
    • Google Cloud 環境外で、サービスアカウントに代わって非公開データにアクセスする

今回想定しているケースでは、エンドユーザになり変わってエンドユーザが権限を持つデータにアクセスすることを想定している。
そのため、「OAuth 2.0 クライアント」を利用するので良さそう。

エンドユーザーとして認証する (OAuth 2.0 クライアント)

エンドユーザーとして認証する  |  Google Cloud

クライアント認証情報の作成

snakasnaka

OAuth 同意画面

不特定多数の Google アカウントを持つユーザを対象とする場合は「外部」を選択する

アプリ情報を入力する

Image from Gyazo

スコープで Google Drive API 関連を選択してみる

Image from Gyazo

各スコープの違い

  • /auth/drive
    • インストールされたアカウントの Google Drive のすべてのファイルにアクセス可能となる
  • /auth/drive.appdata
    • アプリケーション固有の設定情報などが格納されていて、ドライブにアプリケーションがインストールされたときに作成され、アンインストールされたときに削除される
    • ファイルは他の Drive アプリケーションやユーザに対して見えないようになっている
    • https://developers.google.com/drive/api/guides/appdata
  • /auth/drive.file
    • アプリケーションが作成したファイルや、ユーザーが明示的にアクセスを許可したファイルのみがアクセス可能となる
  • /auth/docs
    • ??
  • /auth/drive.metadata
    • ??
snakasnaka

認証情報を用意する

OAuth クライアント ID を用意してみる

作成が完了すると

  • クライアントID
  • クライアントシークレット

が表示される。
また、それらが含まれた JSON がダウンロードできる。

JSONは以下のような構造になっていた

{
  "web": {
    "client_id": "xxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
    "project_id": "xxxxxxxxxxxxxxx",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
    "redirect_uris": [
      "http://localhost:3000/callback"
    ],
    "javascript_origins": [
      "http://localhost:3000"
    ]
  }
}
snakasnaka

OAuth2.0 Play Ground を試す

https://developers.google.com/oauthplayground/

Step1 scope (アクセスを許可するAPI) を選択する

とりあえず Drive API v3 の /auth/drive を許可する

Image from Gyazo

認可フロー

アプリケーションにアクセスを許可する Google アカウントを選択する

Image from Gyazo

アクセス方法について許可を求められるので許可する

Image from Gyazo

リダイレクトで Authrization code が取得できるので、それを Access Token (及び Refresh Token) に交換する

Image from Gyazo

結果として、Access Token と Refrfesh Token が返却されるのでアプリケーション側のストレージ領域(DBやファイルシステム、オブジェクトストレージなど)に保存しておく。

Image from Gyazo

試しに、ファイル一覧を取得してみる

Image from Gyazo

Image from Gyazo

Image from Gyazo

snakasnaka

疑問: トークンの有効期限はアプリケーション側で設定できる?

(TBW)

snakasnaka

サンプルコード

API Console で認証情報を作成する

完全な例 より

require 'google/apis/drive_v2'
require 'google/api_client/client_secrets'
require 'json'
require 'sinatra'

enable :sessions
set :session_secret, 'setme'

get '/' do
  unless session.has_key?(:credentials)
    redirect to('/oauth2callback')
  end
  client_opts = JSON.parse(session[:credentials])
  auth_client = Signet::OAuth2::Client.new(client_opts)
  drive = Google::Apis::DriveV2::DriveService.new
  files = drive.list_files(options: { authorization: auth_client })
  "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
end

get '/oauth2callback' do
  client_secrets = Google::APIClient::ClientSecrets.load
  auth_client = client_secrets.to_authorization
  auth_client.update!(
    :scope => 'https://www.googleapis.com/auth/drive.metadata.readonly',
    :redirect_uri => url('/oauth2callback'))
  if request['code'] == nil
    auth_uri = auth_client.authorization_uri.to_s
    redirect to(auth_uri)
  else
    auth_client.code = request['code']
    auth_client.fetch_access_token!
    auth_client.client_secret = nil
    session[:credentials] = auth_client.to_json
    redirect to('/')
  end
end

(TBW)

作成した結果、 JSON がダウンロードできるので、それを client_secret.json という名前で保存しておく。

実行

$ ruby client.rb                                                                                                                                                                                                     
== Sinatra (v2.2.1) has taken the stage on 4567 for development with backup from Puma
Puma starting in single mode...
* Puma version: 5.6.4 (ruby 3.1.2-p20) ("Birdie's Version")
*  Min threads: 0
*  Max threads: 5
*  Environment: development
*          PID: 9182
* Listening on http://127.0.0.1:4567
* Listening on http://[::1]:4567
Use Ctrl-C to stop
snakasnaka

疑問: オフラインアクセス?

https://developers.google.com/identity/protocols/oauth2/web-server#offline
オフライン アクセスのリクエストは、ユーザーが存在しない場合に Google API にアクセスする必要があるすべてのアプリケーションで必須です。たとえば、バックアップ サービスを実行するアプリや、既定の時間にアクションを実行するアプリは、ユーザーが存在しないときにアクセス トークンを更新できる必要があります。デフォルトのアクセススタイルは online です。

つまり、バッチ処理や非同期処理などでユーザーが介在しない場所での API を実行する場合にアクセストークンを適切に利用するためには offline アクセスが必要ということらしい。

snakasnaka

リダイレクトURI が API Console で指定したものと異なる場合はどうなる?

以下のように「承認エラー」となる

Image from Gyazo

snakasnaka

このアプリは Google で確認されていません

Google に対してアプリの承認プロセスを通していないと表示される?

Image from Gyazo

"続行" のリンクをクリックすると以下の画面に遷移する

Image from Gyazo

snakasnaka

Google Auth ライブラリ

https://github.com/googleapis/google-auth-library-ruby
https://googleapis.dev/ruby/googleauth/latest/

Google::Auth::ClientId とは?

認証情報を用意する で GCP console で作成したクライアント認証情報をコード上で表現したものっぽい。

Google::Auth::Stores::RedisTokenStore とは?

Storage
Authorizers require a storage instance to manage long term persistence of access and refresh tokens. Two storage implementations are included:

  • Google::Auth::Stores::FileTokenStore
  • Google::Auth::Stores::RedisTokenStore

Authorizer には取得したトークンを一定期間保持しておくための保存領域が必要で、その保存方法に応じた TokenStore がSDKとしてあらかじめ用意されているっぽい。
そのうちの一つとして、 Redis に Token を保存するためのクラスが RedisTokenStore

Google::Auth::UserAuthorizer とは?

OAuth2 によるユーザ認証に利用するURLの生成や、認可コードを使ってトークンエンドポイント経由でアクセストークンを取得したりする。

また、取得したアクセストークンは TokenStore を使って一定期間永続化し、必要なタイミングでリトークンのリフレッシュも行ったりする。

Googl::Auth::WebUserAuthorizer とは?

(TBW)

snakasnaka

Application Default Credentials って?

AIP-4110: Application Default Credentials
Google auth libraries use a strategy called Application Default Credentials (ADC) to detect and select credentials based on environment or context. With ADC, developers should be able to run the code in different environments and the supporting systems fetch the appropriate credentials based on each environment in an effortless manner.

アプリケーションは ADC を利用することで、環境毎に認証情報を切り替えるということを意識せずに済む、みたいなことを言っている。

AWS における EC2 や ECS で実行するアプリケーションにAWSリソースにアクセスするための認証情報直接アクセスキーを渡さずに IAM Role をEC2インスタンスやタスクに紐づける仕組みと似ている。

そして ADC を利用できるのは、GCP 上の Compute リソース上でアプリケーションを実行する場合に限られている、というように読める。

Google Cloud でアプリケーションを安全に認証するためのベスト プラクティス

このスクラップは4ヶ月前にクローズされました