OAuth リンクタイプは、インプリシット フローと認可コードフローの 2 通りの業界標準 OAuth 2.0 フローをサポートします。
在隐式代码流程中,Google 会在用户浏览器中打开您的授权端点。成功登录后,系统会向 Google 返回长期访问令牌。现在,从 Google 助理向你的 Action 发送的每个请求中都包含此访问令牌。
在授权代码流程中,您需要两个端点:
- 授权端点,该端点负责向尚未登录的用户显示登录界面,并以短期授权代码的形式记录所请求的访问。
- 令牌交换端点,负责两种类型的交换:
- 将授权代码交换为长期刷新令牌和短期访问令牌。用户完成帐号关联流程后,系统会进行这种交换。
- 将长期刷新令牌换成短期访问令牌。Google 需要新访问令牌时,由于此令牌已过期,因此会进行此交换。
虽然隐式代码流程的实现更简单,但 Google 建议通过隐式流程发出的访问令牌永远不会过期,因为将令牌过期与隐式流程一起使用会强制用户再次关联其帐号。如果出于安全考虑需要令牌到期,强烈建议您考虑使用身份验证代码流程。
OAuth によるアカウント リンクを実装する
プロジェクトを構成する
プロジェクトで OAuth によるアカウント リンクを使用するよう構成するには、次の手順に従います。
- Actions Console を開き、使用するプロジェクトを選択します。
- [Develop](開発)タブをクリックして、[Account linking](アカウント リンク)を選択します。
- [アカウントのリンク] の横にあるスイッチを有効にします。
- [アカウントの作成] セクションで、[いいえ、ウェブサイトでのアカウントの作成のみを許可します。] を選択します。
[Linking type] で、[OAuthOAuth] と [ImplicitOAuth] を選択します。
[Client Information](クライアント情報)で、次の操作を行います。
- [Client ID served by your Actions to Google] に、識別する値を割り当てます。 リクエストの数を減らすことができます。
- 認可エンドポイントとトークン交換エンドポイントの URL を挿入します。
- [保存] をクリックします。
OAuth サーバーを実装する
OAuth 2.0 暗黙的フローをサポートするために、サービスは 使用できます。このエンドポイントは、認証と認可を担当します。 データアクセスについてユーザーから同意を得る。認可エンドポイントは、ログインしていないユーザーにログイン用の UI を表示し、リクエストされたアクセスへの同意を記録します。
アクションからサービスの API を呼び出す必要がある場合、Google はこのエンドポイントを使用して、API の呼び出し許可をユーザーから取得します。
通常、Google が開始する OAuth 2.0 インプリシット フローのセッションは次のような流れになります。
- Google がユーザーのブラウザで認可エンドポイントを開きます。ユーザーがログインし(ログインしていない場合)、Google が API を使用してデータにアクセスすることを承諾します(まだ許可していない場合)。
- サービスがアクセス トークンを作成します。そのトークンを含むリクエストを送信して、ユーザーのブラウザを Google にリダイレクトし、Google にアクセス トークンを返します。
- Google がサービスの API を呼び出し、リクエストごとにアクセス トークンを関連付けます。サービスは、アクセス トークンによって API へのアクセスが Google に許可されていることを確認し、API 呼び出しを完了します。
認可リクエストの処理
アクションで OAuth2 インプリシット フローを介してアカウント リンクを行う必要がある場合、Google は、次のパラメータを含むリクエストを使用して、ユーザーを認可エンドポイントに送信します。
| 認可エンドポイントのパラメータ | |
|---|---|
client_id |
Google に割り当てたクライアント ID。 |
redirect_uri |
このリクエストに対するレスポンスを送信する URL。 |
state |
リダイレクト URL で変更されずに Google に返される会計上の値。 |
response_type |
レスポンスで返される値のタイプ。OAuth 2.0 暗黙の API では、
レスポンス タイプは常に token です。 |
たとえば、認可エンドポイントが https://myservice.example.com/auth にある場合、
次のようなリクエストになります。
GET https://myservice.example.com/auth?client_id=GOOGLE_CLIENT_ID&redirect_uri=REDIRECT_URI&state=STATE_STRING&response_type=token
認可エンドポイントでログイン リクエストを処理する場合は、次の手順に従います。
client_idとredirect_uriの値を検証する 意図しないクライアント アプリへのアクセスや構成ミスのあるクライアント アプリclient_idが、指定したクライアント ID と一致することを確認します。 割り当てられていますredirect_uriで指定された URL を確認します。 パラメータの形式は次のとおりです。 YOUR_PROJECT_ID は、[プロジェクトの設定] ページにある ID です。 確認できます。https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID
ユーザーがサービスにログインしているかどうか確認します。ユーザーがログインしていない場合は、サービスのログインまたは登録フローを完了します。
Google が API へのアクセスで使用するアクセス トークンを生成します。アクセス トークンには任意の文字列値を設定できますが、トークンを使用するユーザーとクライアントを一意に表し、簡単に推測されない文字列にする必要があります。
ユーザーのブラウザを URL にリダイレクトする HTTP レスポンスを送信する
redirect_uriパラメータで指定します。URL フラグメントに次のパラメータをすべて含めます。access_token: 生成したアクセス トークンtoken_type: 文字列bearerstate: 元の状態から変更されていない状態の値 リクエスト 結果の URL の例を次に示します。https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID#access_token=ACCESS_TOKEN&token_type=bearer&state=STATE_STRING
Google の OAuth 2.0 リダイレクト ハンドラがアクセス トークンを受け取り、
state 値が変更されていないことを確認します。Google は、
そのトークンを後続の呼び出しにアタッチします。
AppRequest の一部としてアクションに渡します。
認証フローを開始する
アカウント ログイン ヘルパー インテントを使用して認証フローを開始します。次のコード スニペットは、Dialogflow と Actions SDK でこのヘルパーを使用してレスポンスを送信する方法を示します。
Dialogflow:
<ph type="x-smartling-placeholder">const {dialogflow, SignIn} = require('actions-on-google'); const app = dialogflow({ // REPLACE THE PLACEHOLDER WITH THE CLIENT_ID OF YOUR ACTIONS PROJECT clientId: CLIENT_ID, }); // Intent that starts the account linking flow. app.intent('Start Signin', (conv) => { conv.ask(new SignIn('To get your account details')); });
@ForIntent("Start Signin") public ActionResponse text(ActionRequest request) { ResponseBuilder rb = getResponseBuilder(request); return rb.add(new SignIn().setContext("To get your account details")).build(); }
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "PLACEHOLDER" } } ] }, "userStorage": "{\"data\":{}}", "systemIntent": { "intent": "actions.intent.SIGN_IN", "data": { "@type": "type.googleapis.com/google.actions.v2.SignInValueSpec", "optContext": "To get your account details" } } } }, "outputContexts": [ { "name": "/contexts/_actions_on_google", "lifespanCount": 99, "parameters": { "data": "{}" } } ] }
Actions SDK:
<ph type="x-smartling-placeholder">const {actionssdk, SignIn} = require('actions-on-google'); const app = actionssdk({ // REPLACE THE PLACEHOLDER WITH THE CLIENT_ID OF YOUR ACTIONS PROJECT clientId: CLIENT_ID, }); // Intent that starts the account linking flow. app.intent('actions.intent.TEXT', (conv) => { conv.ask(new SignIn('To get your account details')); });
@ForIntent("actions.intent.TEXT") public ActionResponse text(ActionRequest request) { ResponseBuilder rb = getResponseBuilder(request); return rb.add(new SignIn().setContext("To get your account details")).build(); }
{ "expectUserResponse": true, "expectedInputs": [ { "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "PLACEHOLDER" } } ] } }, "possibleIntents": [ { "intent": "actions.intent.SIGN_IN", "inputValueData": { "@type": "type.googleapis.com/google.actions.v2.SignInValueSpec", "optContext": "To get your account details" } } ] } ], "conversationToken": "{\"data\":{}}", "userStorage": "{\"data\":{}}" }
データアクセス リクエストを処理する
アシスタントのリクエストにアクセス トークンが含まれている場合は、まずそのアクセス トークンが有効で期限切れになっていないことを確認してから、関連付けられているユーザー アカウントをデータベースから取得します。