학습서: 세션 중에 사용자 인증

웹 대화 보안을 사용하는 경우 메시지에 서명하는 데 사용하는 JWT (JSON Web Token) 의 일부로 세션 시작 시 고객의 사용자 ID를 설정해야 합니다. 인증되지 않은 사용자의 경우, 이는 일반적으로 생성된 ID이며 JWT가 작성된 후에는 변경할 수 없습니다. 그러나 개인용 변수를 사용하여 나중에 세션에서 사용자를 인증할 수 있습니다.

웹 대화 보안을 사용하는 경우 각 메시지와 연관된 사용자 ID는 JWT 페이로드의 sub 청구를 기반으로 합니다. 이 값은 JWT가 작성될 때 세션 시작 시 설정되어야 하며 세션의 수명 동안 변경될 수 없습니다. 인증되지 않은 (익명) 사용자의 경우, 일반적으로 쿠키에 저장된 생성된 ID를 사용하여 각 고유 고객이 청구 목적으로 한 번만 계수되도록 합니다.

그러나 고객이 세션 중에 인증할 수 있도록 할 수 있습니다 (예를 들어, 사용자의 계정 정보를 업데이트하는 조치를 완료하기 위해). sub 청구에서 생성된 사용자 ID를 변경할 수 없으므로 사용자를 안전하게 인증하는 다른 방법이 필요합니다. 고객의 실제 인증된 사용자 ID를 JWT의 사용자 페이로드에 개인용 변수로 저장하여 이를 수행할 수 있습니다. (일반 컨텍스트 변수에 사용자 ID를 저장할 수 있지만 이러한 변수를 수정할 수 있으므로 안전하지 않습니다.)

이 학습서에 설명된 예제의 전체 작동 버전은 watsonx Assistant 웹 대화(복합)에 대한 보안 사용을 참조하십시오.

세션 중에 페이로드 및 사용자 변경사항을 암호화하지 않은 보안을 사용하기 위한 최소 코드의 웹 대화 버전은 watsonx Assistant 웹 대화(단순)에 대한 보안 사용을 참조하십시오.

Node.js용 Express 서버를 기반으로 하는 이 학습서의 이 예제에서는 익명 사용자 ID로 세션을 시작한 후 세션 중에 사용자를 인증하는 방법을 보여줍니다.

  1. 각 고객에 대해 고유한 익명 사용자 ID를 생성하고 이를 쿠키에 저장하는 getOrSetAnonymousID() 라는 함수를 작성하십시오 (또는 쿠키가 이미 있는 경우 저장된 사용자 ID를 사용함).

    45일이상 지속되는 쿠키를 사용하십시오. 30일이상 사용자 ID를 저장하지 않으면 동일한 청구 기간 동안 동일한 고객이 여러 다른 사용자로 계수될 수 있습니다. (이는 동일한 사용자가 쿠키를 삭제하거나 다른 브라우저를 사용하는 경우에도 계속 발생할 수 있습니다.)

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() 함수를 호출하여 user_payload 청구를 채우기 위해 업데이트된 세션 정보를 사용하여 JWT를 다시 생성하십시오.

    예제에서 인증은 간단한 단추 클릭으로 시뮬레이션됩니다. 또한 동일한 단추가 쿠키를 삭제하여 로그아웃을 시뮬레이션합니다.

    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 웹 대화에 대한 보안 사용 예제를 참조하십시오.

GDPR 요구사항을 준수해야 하는 경우, 특히 나중에 사용자 신임 정보를 사용하여 로그인하는 익명 사용자의 경우 생성된 익명 사용자 ID를 지속적으로 저장해야 할 수 있습니다. 이러한 사용자 ID를 저장하면 나중에 개인 고객과 연관된 모든 데이터를 삭제하도록 요청된 경우 이를 삭제할 수 있습니다.