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

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

ウェブチャットのセキュリティを有効にすると、各メッセージに関連付けられたユーザーIDは、JWTペイロードの'subクレームに基づいている。 この値は、JWTが作成されるセッションの開始時に設定されなければならず、セッションの存続中に変更することはできない。 認証されていない(匿名)ユーザーに対しては、通常、生成されたIDを使用し、クッキーに保存し、各ユニークな顧客が課金目的で一度だけカウントされるようにします。

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

このチュートリアルで説明する例の完全な実用版については、AIアシスタントのウェブチャットのセキュリティを有効にする(複雑)を参照してください。

暗号化されたペイロードとセッション中のユーザー変更を持たない、セキュリティを有効にするための最小限のコードを持つウェブチャットバージョンについては、AIアシスタントウェブチャットのセキュリティを有効にする(シンプル)を参照してください。

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

  1. getOrSetAnonymousID()と呼ばれる関数を作成し、顧客ごとに一意の匿名ユーザーIDを生成してクッキーに保存します(クッキーがすでに存在する場合は、保存されたユーザーIDを使用します)。

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

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クッキーから任意の値を取得してください。 値が存在する場合、それをJWTの'user_payloadプライベート・クレームに格納する。 (ユーザーがまだ認証されていない場合、このクッキーはまだ存在しません)

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クッキーに保存する。
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クッキーに保存する。 その後、'createJWT()関数を呼び出してJWTを再生成し、更新されたセッション情報を使って'user_payloadクレームに入力する。

    この例では、認証は単純なボタンクリックでシミュレートされる。 同じボタンで、クッキーを削除してログアウトすることもできます:

    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

完全な動作コードについては、AIアシスタントウェブチャットのセキュリティを有効にする例を参照してください。

GDPRの要件に準拠する必要がある場合、生成された匿名ユーザーIDを永続的に保存する必要があるかもしれません。 これらのユーザーIDを保存しておくことで、後で要求があった場合に、個々の顧客に関連するすべてのデータを削除することが可能になります。