チュートリアル: セッションの途中でユーザーの認証を行う

Web チャット・セキュリティーが有効になっている場合は、メッセージに署名するために使用する JSON Web トークン (JWT) の一部として、セッションの開始時に顧客のユーザー ID を設定する必要があります。 認証されていないユーザーの場合、これは通常は生成された ID であり、JWT の作成後に変更することはできません。 ただし、プライベート変数を使用して、後でセッションでユーザーを認証することができます。

Web チャット・セキュリティーが有効になっている場合、各メッセージに関連付けられたユーザー ID は、JWT ペイロード内の sub クレームに基づきます。 この値は、JWT の作成時にセッションの開始時に設定する必要があり、セッションの存続中に変更することはできません。 非認証 (匿名) ユーザーの場合、通常は、Cookie に保存された生成された ID を使用して、固有の各顧客が請求処理の目的で 1 回のみカウントされるようにします。

ただし、顧客がセッションの途中で認証できるようにしたい場合があります (例えば、ユーザーのアカウント情報を更新するアクションを実行する場合など)。 sub クレーム内に生成されたユーザー ID は変更できないため、ユーザーを安全に認証する別の方法が必要です。 これを行うには、お客様の実際の認証済みユーザー ID をプライベート変数として JWT のユーザー・ペイロードに保管します。 (ユーザー ID を通常のコンテキスト変数に保管することはできますが、そのような変数は変更できるため、これは安全ではありません。)

このチュートリアルで説明する例の完全な作業バージョンについては、 watsonx Assistant Web チャット(複合)のセキュリティーの有効化を参照してください。

セッション中に暗号化されたペイロードやユーザー変更がないセキュリティーを有効にする最小コードの Web チャット・バージョンについては、 watsonx Assistant Web チャット(シンプル)のセキュリティーの有効化を参照してください。

このチュートリアルの例は、 Node.jsの Express サーバーに基づいており、匿名ユーザー ID を使用してセッションを開始し、セッション中にユーザーを認証する方法を示しています。

  1. 顧客ごとに固有の匿名ユーザー ID を生成し、それを Cookie に保管する getOrSetAnonymousID() という関数を作成します (Cookie が既に存在する場合は、保管されているユーザー ID を使用します)。

    少なくとも 45 日間存続する Cookie を使用してください。 30 日を超えてユーザー ID を保管しないと、同じ顧客が同じ請求期間中に複数の異なるユーザーとしてカウントされる可能性があります。 (これは、同じユーザーが Cookie を削除した場合、または別のブラウザーを使用した場合にも発生する可能性があります。)

function getOrSetAnonymousID(request, response) {
  let anonymousID = request.cookies['ANONYMOUS-USER-ID'];
  if (!anonymousID) {
    anonymousID = `anon-${uuid()}`;
  }

  response.cookie('ANONYMOUS-USER-ID', anonymousID, {
    expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 45), // 45 days.
    httpOnly: true,
  });

  return anonymousID;
}
  1. JWT の作成に使用する関数では、 getOrSetAnonymousID() 関数から返された匿名 ID を sub クレームの値として使用します。 これは、請求の目的で顧客を一意的に識別するために使用されるユーザー ID の値を設定します。

    さらに、認証されたログイン情報を保管するために使用する SESSION_INFO Cookie から任意の値を取得します。 値が存在する場合は、その値を JWT の user_payload プライベート・クレームに保管します。 (ユーザーがまだ認証されていない場合、この Cookie はまだ存在しません。)

const jwtContent = {
  sub: anonymousUserID,
  user_payload: {
    name: 'Anonymous',
    custom_user_id: anonymousUserID,
  },
};

if (sessionInfo) {
  jwtContent.user_payload.name = sessionInfo.userName;
  jwtContent.user_payload.custom_user_id = sessionInfo.customUserID;
}
  1. ユーザー認証を処理する機能を作成します。 この例では、ハードコーディングされたユーザー ID を設定する単純な authenticate() 関数を使用していますが、実際のアプリケーションでは、セキュア認証検査後にユーザー ID がデータベースから取得される可能性があります。 ユーザー情報を SESSION_INFO Cookie に保管します。
function authenticate(request, response) {

  const userInfo = {
    userName: 'Cade',
    customUserID: 'cade-id',
  };

  response.cookie('SESSION_INFO', JSON.stringify(userInfo), { encode: String });

  response.send('Ok');
}
  1. ユーザーがログインするときに、 authenticate() 関数を呼び出して、ユーザー情報を SESSION_INFO Cookie に保管します。 次に、 createJWT() 関数を呼び出して、更新されたセッション情報を使用して user_payload クレームにデータを取り込み、JWT を再生成します。

    この例では、ボタンをクリックするだけで認証がシミュレートされます。 また、同じボタンを使用すると、Cookie を削除してログアウトをシミュレートすることもできます。

    async function onClick() {
      if (getCookieValue('SESSION_INFO')) {
        document.cookie = 'SESSION_INFO=; Max-Age=0';
      } else {
        await fetch('http://localhost:3001/authenticate');
      }
    
      const result = await fetch('http://localhost:3001/createJWT');
      const newToken = await result.text();
    
      webChatInstance.updateIdentityToken(newToken);
    
      updateUI();
    }
    

    sub クレーム内の匿名 ID は、請求の目的で顧客を追跡するために引き続き使用されますが、顧客の実ユーザー ID はユーザー・ペイロードに個別に保管されるようになりました。

  2. アクションで、 user_payload 専用コンテキスト変数を参照することにより、顧客の実ユーザー ID にアクセスできるようになりました。

${system_integrations.chat.private.user_payload}.custom_user_id

完全な作業コードについては、 watsonx Assistant Web チャットのセキュリティーの有効化 の例を参照してください。

GDPR 要件に準拠する必要がある場合は、生成された匿名ユーザー ID を永続的に保管する必要があります (特に、後でユーザー資格情報を使用してログインする匿名ユーザーの場合)。 これらのユーザー ID を保管すると、個々の顧客に関連付けられているすべてのデータを後で削除するように要求された場合に、削除することができます。