多分頁、多裝置同步:登出、權限與購物車
一次登出所有地方、撤銷的角色立即生效,並讓購物車與設定在使用者開著的每個分頁和裝置上保持一致。
使用者常在好幾個分頁、好幾台裝置上開著你的應用,而每一份都要重新整理才知道有變化。有人在共用電腦上登出了,手機上的分頁卻還顯示他的帳號。管理員撤掉了同事的編輯權限,同事卻能一直編輯到重新整理為止。手機上把商品加進購物車,筆電的分頁卻還說購物車是空的。用 Hibira,你的伺服器能一次通知應用的每一份副本。
使用者得到什麼
- 「登出所有裝置」真的會立刻關閉每個打開的工作階段。
- 角色變更或權限撤銷不必重新整理就生效。
- 每個分頁、每台裝置上的購物車、設定和未讀數都一致。
用到的功能
- 使用者驗證(
pusher.signin()),做法同即時站內通知,讓每個登入的連線都屬於某位使用者。 sendToUser,一次呼叫就送到這位使用者的每個分頁和裝置。terminateUserConnections,關閉以這位使用者登入的每個連線。
某位使用者的資料變了
你的伺服器登出、新角色、購物車
sendToUser()Hibira
WebSocket
每個分頁和裝置屬於這位使用者
登出所有裝置
你的伺服器工作階段已撤銷
全部斷線
Hibira
關閉
每個連線以這位使用者登入
步驟 1:登出所有裝置
先在資料庫撤銷工作階段,再通知每一份打開的應用,最後關閉連線:
app.post('/account/sign-out-everywhere', requireLogin, async (req, res) => {
const id = String(req.user.id);
await db.sessions.revokeAll(id);
await pusher.sendToUser(id, 'signed-out', {});
await pusher.terminateUserConnections(id);
res.sendStatus(204);
});被關閉的連線無法再次登入,因為你的使用者驗證端點已經不接受被撤銷的工作階段。
步驟 2:權限變更立刻生效
管理員變更某人的角色時,送出一個提醒。頁面會向你的伺服器重新取得權限,伺服器仍然是唯一的依據:
await db.members.update(member.id, { role: 'viewer' });
await pusher.sendToUser(String(member.userId), 'permissions-changed', {});步驟 3:讓每個地方的購物車都一樣
每次購物車變動後,送出頁首要顯示的摘要:
app.post('/api/cart/items', requireLogin, async (req, res) => {
const cart = await db.carts.add(req.user.id, req.body);
await pusher.sendToUser(String(req.user.id), 'cart', { count: cart.count, total: cart.total });
res.json(cart);
});步驟 4:在每個分頁做出反應
pusher.user.bind('signed-out', () => location.assign('/login'));
pusher.user.bind('permissions-changed', async () => {
applyPermissions(await fetch('/api/me/permissions').then((r) => r.json()));
});
pusher.user.bind('cart', ({ count, total }) => cartBadge.set(count, total));小提醒
- 安全上不要相信事件本身:它只代表「請重新檢查」。你的 API 仍然要在每個請求檢查工作階段和角色。
BroadcastChannel能同步同一個瀏覽器的分頁,但無法同步其他裝置,也收不到管理員或伺服器做的變更。- 訪客購物車可以一個購物車一個私人頻道(
private-cart-<id>),用購物車的 cookie 授權。 - 送數量和總額就好,不要送整個購物車;事件大小依方案而定,請看價格。