# 裝置指紋

本頁說明 Token 綁定的裝置指紋如何產生、在哪裡比對，以及偵測規則的實際行為。

## 產生方式

`CreateFingerprint()`（`src/CreateFingerprint.ts`）把下列四個值組成 JSON，再取 SHA-256 hex：

| 欄位 | 來源 |
|---|---|
| `os` | User-Agent 比對 |
| `browser` | User-Agent 比對 |
| `device` | User-Agent 比對 |
| `deviceId` | `X-Device-ID` header → `req.body.deviceId` → `"Unknown"` |

若 `req.session.fp` 存在（例如以 `express-session` 自行保存），所有 API 直接使用該值，不重新計算。

## 偵測規則

比對依表格由上而下，**第一個命中即採用**：

| 欄位 | 順序 |
|---|---|
| `os` | `Windows` → `Macintosh\|Mac OS X` → `Linux` → `Android` → `iPhone\|iPad\|iPod` → `Unknown_OS` |
| `browser` | `Edge\|Edg` → `Firefox` → `Chrome` → `Safari` → `Opera\|OPR` → `Unknown_Browser` |
| `device` | `iPad` → `iPhone\|iPod\|Android.*Mobile\|BlackBerry\|IEMobile\|Opera Mini` → `Desktop` |

因為先命中即停止，部分結果與直覺不同：

| User-Agent | 實際結果 | 原因 |
|---|---|---|
| Android | `os: Linux` | Android UA 含 `Linux`，排在 `Android` 之前 |
| iPhone／iPad | `os: MacOS` | iOS UA 含 `like Mac OS X` |
| Opera | `browser: Chrome` | Opera UA 含 `Chrome` |

這些值只用來產生雜湊，同一裝置每次得到相同結果即可，不影響綁定效果。

## 比對位置

| 時機 | 不符時的結果 |
|---|---|
| 有效 Access Token 的 `fp` | `isError: true` |
| 過期 Access Token 解碼後的 `fp` | `isError: true` |
| Redis Refresh 資料的 `fp` | `isError: false`（訪客） |

相關：[Token 傳遞](/zh/token-transport)、[客戶端整合](/zh/client-integration)
