教程: 在会话中间认证用户
如果已启用 Web 聊天安全性,那么必须在会话开始时将客户的用户标识设置为用于签署消息的 JSON Web 令牌 (JWT) 的一部分。 对于未认证的用户,这通常是生成的标识,在创建 JWT 后无法对其进行更改。 但是,您可以在稍后的会话中使用专用变量来认证用户。
启用 Web 聊天安全性后,与每条消息关联的用户标识将基于 JWT 有效内容中的 sub
声明。 必须在会话开始时 (创建 JWT 时) 设置此值,并且在会话生命周期内不能更改此值。 对于未经认证 (匿名) 的用户,您通常会使用已生成的标识 (保存到 cookie 中) 来确保每个唯一客户仅计数一次以进行计费。
但是,您可能希望客户能够在会话中间进行认证 (例如,完成更新用户帐户信息的操作)。 由于无法更改 sub
声明中生成的用户标识,因此您需要另一种方法来安全地认证用户。 您可以通过将客户的实际已认证用户标识作为专用变量存储在 JWT 的用户有效内容中来执行此操作。 (您可以将用户标识存储在普通上下文变量中,但这将不安全,因为可以修改此类变量。)
要获取本教程中描述的示例的完整工作版本,请参阅 为 watsonx Assistant Web 聊天(复杂)启用安全性。
对于具有最低代码以启用安全性的 Web 聊天版本 (在会话期间没有加密有效内容和用户更改),请参阅 对 watsonx Assistant Web 聊天启用安全性(简单)。
本教程中的此示例 (基于 Node.js的 Express 服务器) 显示了如何使用匿名用户标识启动会话,然后在会话期间对用户进行认证。
-
创建名为
getOrSetAnonymousID()
的函数,该函数为每个客户生成唯一的匿名用户标识,并将其存储在 cookie 中 (或者,如果 cookie 已存在,那么使用存储的用户标识)。使用至少持续 45 天的 cookie。 如果存储用户标识的时间不超过 30 天,那么同一客户可能会在同一计费周期内计为多个不同的用户。 (如果同一用户删除 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;
}
-
在用于创建 JWT 的函数中,使用从
getOrSetAnonymousID()
函数返回的匿名标识作为sub
声明的值。 这将设置将用于唯一标识客户以进行计费的用户标识的值。此外,从
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;
}
- 创建用于处理用户认证的函数。 在我们的示例中,我们使用的是设置硬编码用户标识的简单
authenticate()
函数,但在实际应用程序中,用户标识可能会在安全认证检查后从数据库中检索。 将用户信息存储在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');
}
-
用户登录时,调用
authenticate()
函数以将用户信息存储在SESSION_INFO
cookie 中。 然后,使用更新的会话信息来填充user_payload
声明,调用createJWT()
函数以重新生成 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
声明中的匿名标识将继续用于跟踪客户以进行计费,但现在客户的真实用户标识将单独存储在用户有效内容中。 -
在您的操作中,现在可以通过引用
user_payload
专用上下文变量来访问客户的实际用户标识:
${system_integrations.chat.private.user_payload}.custom_user_id
有关完整的工作代码,请参阅 对 watsonx Assistant Web chat 启用安全性 示例。
如果要求您遵守 GDPR 要求,那么可能需要持久存储任何生成的匿名用户标识,尤其是对于稍后使用用户凭证登录的匿名用户。 通过存储这些用户标识,您可以在以后根据请求删除与单个客户关联的所有数据。