客人验证流程
本指南说明如何在认证门户中使用在住客人名单:如何将客人输入的信息与名单匹配、Wi-Fi 会话应何时结束、名单应多久刷新一次,以及为土耳其第 5651 号法律日志应保留哪些字段。
认证门户上应询问什么#
由于名单同时提供房间和身份信息,最常见的形式是房间号 + 姓氏。仅凭房间号是不够的:任何知道隔壁房间号的人都能登录。其他可选方式有房间号 + 身份证/护照号或姓氏 + 出生日期;后者可作为证件号码为空的客人的备用方式。
匹配规则#
将客人输入的内容与名单中的值进行比较之前,先对双方进行规范化处理:
- 房间号:去除首尾空白并转换为大写。
roomName是字符串(可能是"104"、"A-12"或"Villa 3");不要将其转换为数字,也不要去掉前导零。 - 姓氏:转换为大写(注意土耳其语的
i → İ映射),并将连续空格合并为一个。名单中的值通常取自证件,为大写。 - 证件号码:去除空格并转换为大写。土耳其公民身份证号为 11 位数字;护照号由字母和数字混合组成。
- 出生日期:名单中为
DD.MM.YYYY格式;如果您的表单采用其他格式,请进行转换。
const norm = (s) => String(s ?? "")
.replace(/\s+/g, " ")
.trim()
.toLocaleUpperCase("tr-TR");
function findGuest(list, room, lastName) {
return list.find((g) =>
norm(g.roomName) === norm(room) && norm(g.lastName) === norm(lastName)
) || null;
}
const guest = findGuest(data.otelde, form.room, form.lastName);
if (!guest) {
// "房间号与姓氏不匹配" — 统计失败次数, 5 次后限流
}匹配记录的 unique 值即热点用户的身份标识。同一位客人从第二台设备登录时,请沿用与该值关联的账户,而不是新建账户,并在该账户上执行设备数量限制。
会话时长#
checkout 是计划退房日期,指向当天的 00:00(UTC),不含具体时刻。如果会话只开放到这一时刻,客人在离店当天早上就会失去访问权限。请在该日期上加上酒店的退房时间来计算会话结束时间:
const CHECKOUT_TIME = "12:00"; // 酒店的退房时间
const day = new Date(guest.checkout * 1000)
.toLocaleDateString("en-CA", { timeZone: "UTC" }); // "2026-09-10"
const sessionEnd = new Date(`${day}T${CHECKOUT_TIME}:00+03:00`);如果客人在退房时间之前离店,就会从名单中消失;请在下一次同步时关闭其账户。如果住宿延长,checkout 会发生变化;请在同步时比较该字段并更新会话结束时间。对于延迟退房的情况,只要客人仍在名单中就保持访问权限,这样更稳妥。
定期同步#
名单只是一个快照,没有变更通知(webhook)。请按固定间隔获取名单,并按 unique 与上一份名单进行比对:
- 间隔:对大多数酒店来说 5 分钟足够。如果希望客人一办理入住就能上网,可以缩短到 1–2 分钟;但不要低于 1 分钟。
- 新出现的
unique:预先准备账户;客人首次在认证门户登录时完成匹配。 - 消失的
unique:客人已退房或预订已取消。结束会话并关闭账户。 unique相同,但roomName或checkout不同:换房或续住。更新账户。- 请求失败:遇到超时、
401或5xx时,保留上一次成功获取的名单;切勿根据错误响应关闭账户。
async function sync(prev) {
const res = await fetch(BASE + "/public/json/customer/inhotel", {
method: "POST",
headers: { "ApiKey": process.env.HMS_API_KEY, "HotelCode": HOTEL_CODE }
});
if (!res.ok) return prev; // 401 / 5xx: 保留旧名单
const { success, otelde } = await res.json();
if (success !== 1) return prev;
const next = new Map(otelde.map((g) => [g.unique, g]));
for (const [id] of prev) {
if (!next.has(id)) await closeAccount(id); // 已退房
}
for (const [id, g] of next) {
const old = prev.get(id);
if (!old) await openAccount(g); // 新客人
else if (old.checkout !== g.checkout || old.roomName !== g.roomName) await updateAccount(g);
}
return next;
}一个房间住多位客人#
同一房间内的每位客人都是一条独立记录:rezervasyon_id 相同,unique 不同。请按客人而不是按房间开通账户,使每位客人拥有各自的设备、会话和第 5651 号法律日志记录。对于同姓的客人(例如一家人),按房间号 + 姓氏查询可能返回多条记录;此时不要直接取第一条匹配结果,而应通过名字或出生日期加以区分,或为他们开通一个共享账户。
第 5651 号法律日志#
按土耳其第 5651 号法律留存访问日志的义务由热点系统承担,HMS 只提供身份数据。会话开启时,请将以下字段与 MAC/IP 地址和时间戳一起保存:unique、rezervasyon_id、firstName、lastName、identityNumber、birthDate、roomName、checkin、checkout。客人从名单中消失后,HMS 将不再提供这些信息,因此请在您一方保留记录。