0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Alexa 音声でアカウントリンクする - Voice-Forward Account Linking -

Posted at

前提

  • スキルのモデル
    • カスタムスキルのみ
  • アカウントリンク設定
    • ユーザーが音声を使用して自分のアカウントをスキルにリンクすることを許可するをオンにする
  • ユーザー認証
    • Login with Amazon (LWA) のみ
  • アクセス権限
    • ユーザー名(姓名または名前)をオンにする
    • スキルのパーソナライズはオフにする
  • ユーザープロフィール
    • ユーザーのプロフィールに電話番号が登録されている

キーワード

  • Account Linking
  • Login with Amazon (LWA)
  • Skill Connections

実装手順

  • プロフィールの確認
  • セキュリティプロファイルの設定
  • スキルの設定
  • コード作成

プロフィールの確認

アカウント所有者に対して、電話番号が登録されていないと以下のようなエラーが出て Voice-Forward Account Linking が使用できないので、まずはここを確認する。

The user hasn't specified phone number necessary to validate their account linking request.

家族アカウントがたくさんあってどれがアカウント所有者かわからなくなってしまった場合は、:busts_in_silhouette: プロフィール管理画面で確認できる。プロフィールの詳細を開いて アカウント管理者 と書いてあるアカウントを探す。また、プロフィールを作り過ぎてしまってAlexaアプリでプロフィール消せずに困っている場合はここで削除することができる。Alexaアプリでは削除ができない。

image.png

 アカウント所有者 普通のユーザー

不要なアカウントを消したはいいけど、Alexaアプリで以下のようなエラーがでるようになってしまったら、Alexaアプリをサインアウトすることで元にもどる。

image.png

セキュリティプロファイルの設定

Login With Amazonの設定。新規作成して必要情報を入力するだけ。簡単です。

参考:LWAでセキュリティプロファイルを作成

image.png

スキルの設定

Devloper Console の ツールアカウントリンク から、ユーザーが音声を使用して自分のアカウントをスキルにリンクすることを許可するをオンにする。

当然ユーザーがアカウントや既存アカウントへのリンクを作成することを許可しますか? もオンにしておく。
アカウントリンクなしでスキルを有効にすることをユーザーに許可します (推奨)。これもオンにしておく。そうしないと、Alexaアプリでスキルを有効化した時にアカウントリンクを求められるため。

image.png

Auth Code Grant に、セキュリティプロファイルの値を設定する。

image.png

Devloper Console の ツールアクセス権限 で、ユーザー名(姓名または名前)をオンにする。また、スキルのパーソナライズがオンになっていると、音声によるアカウントリンクができないので、これはオフにしておく。

image.png

コード作成

設定ができていれば、サンプルコードをコピペするだけで動く。サンプルコードやステータスは以下に記載されている。

参考:Voice-Forward Account Linking Implementation Details (LWA)

responseBuilder で 下記のディレクティブを設定するだけです。下記の例は LaunchRequestHandler に記載していますが、アカウントリンクが必要なハンドラーのresponseBuilderに記載すればOKです。Skill Connections の機能を利用してAmazon側に処理を投げる。

addDirective
const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
    },
    handle(handlerInput) {
        const accessToken = handlerInput.requestEnvelope.context.System.user.accessToken;
        console.log(`accessToken: ${JSON.stringify(accessToken)}`);
        if (accessToken === undefined){
            //Account is not linked
            return handlerInput.responseBuilder
            .speak('音声によるアカウントリンクを開始します。')
            .addDirective({
                'type': 'Connections.StartConnection',
                'uri': 'connection://AMAZON.AskForAccountLinking/1',
                'onCompletion': 'RESUME_SESSION',
                'input': {
                    '@version': '1',
                    '@type': 'AskForAccountLinking'
                },
                'token': 'accountLinking'
                // Token can be anything that can be used to identify the request on session resumption
            })
            .getResponse();
        }else{
            // Handle the account already linked flow.
        }
    }
};

Amazon側で処理が完了したら、SessionResumedRequest というリクエストが送信されてくるので、このリクエストを受け取るハンドラーを作っておく必要がある。これもサンプル通り。他のSkill Connectionsのリクエストと区別できるように、request.cause.token === 'accountLinking'を条件に加えられている。

SessionResumedRequest
const AccountLinkingSessionResumedHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionResumedRequest' && request.cause.token === 'accountLinking'; // Token needs to be same as passed in request
    },
    handle(handlerInput) {
       console.log(`AccountLinkingSessionResumedHandler: ${JSON.stringify(handlerInput)}`);
       const status = handlerInput.requestEnvelope.request.cause.status;
       const code = status.code;
       const message = status.message;
       console.log(`AccountLinkingSessionResumedHandler received status code : ${code} and message : ${message}`);

       const accountLinkingStatus = handlerInput.requestEnvelope.request.cause.result.status;

       if (code !== '200'){
        //Error occured in the request
        //Response
        return handlerInput.responseBuilder
            .speak('リクエストでエラーが発生しました。')
            .withLinkAccountCard()
            .getResponse();
       }

       // Now check to see if the user passed or failed account linking.
       const accountLinkingTaskResult = handlerInput.requestEnvelope.request.cause.result;
       const accountLinkingTaskStatus = accountLinkingTaskResult.status;        
       console.log(`accountLinkingTaskStatus: ${JSON.stringify(accountLinkingTaskStatus)}`);
       if (accountLinkingTaskStatus === 'LINKED') {
           // Account was linked or is linked successfully as part of the request
           // <HANDLE_LINKED>
           //Response
       var accessToken = handlerInput.requestEnvelope.context.System.user.accessToken;

        // Logic to look up or create account if necessary
            // If you have a resource server that makes call internally to LWA to get the LWA ID
            // makeHttpCall('resource_server',accessToken);

            // If you need LWA_ID for your operation
            // https://developer.amazon.com/docs/login-with-amazon/obtain-customer-profile.html#call-profile-endpoint
            // makeHttpCall('https://api.amazon.com/user/profile?access_token=*',accessToken);
            // Use LWA_ID from the request above to look up or create an account as necessary

            // If you need customer contact information, use the Alexa Customer Profile API
            // https://developer.amazon.com/en-US/docs/alexa/custom-skills/request-customer-contact-information-for-use-in-your-skill.html

            return handlerInput.responseBuilder
                .speak('アカウントがリンクされました。')
                .getResponse();

        } else if (accountLinkingTaskStatus === 'DENIED') {
            // User denied the account linking permissions on request or sharing the information with the skill, hence the account linking flow failed.

            // <HANDLE_DENIED>
            //Response
            return handlerInput.responseBuilder
                .speak('アカウントリンクができませんでした。。')
                .withLinkAccountCard()
                .getResponse();

        } else if (accountLinkingTaskStatus === 'NOT_ANSWERED') {
            // The user did not answer the question, asked as part of the skill.
            // <HANDLE_NOT_ANSWERED>
            //Response
            return handlerInput.responseBuilder
                .speak('ユーザーからの答えがありませんでした。。')
                .withLinkAccountCard()
                .getResponse();
        } else if (accountLinkingTaskStatus === 'USER_REQUIREMENTS_NOT_MET'){
            // The request was cancelled because the voice account linking flow can't be triggered for the customer or can't be completed.
            // <HANDLE_USER_REQUIREMENTS_NOT_MET>
            //Response
            return handlerInput.responseBuilder
                .speak('リクエストがキャンセルされました。')
                .withLinkAccountCard()
                .getResponse();
        }

    }
};

こんな感じで、音声でアカウントリンクさせることができる。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?