53 lines
1.7 KiB
JavaScript
53 lines
1.7 KiB
JavaScript
/**
|
||
* 设备指纹(spec §9.1 v2.3 限流维度 — X-Device-Fingerprint)
|
||
*
|
||
* 为什么不复用 push cid(uni.getPushClientId 拿到的 cid):
|
||
* - push cid 在推送 SDK 升级 / 推送通道重连时会变 → 限流计数被误清零
|
||
* - 小程序/H5 端无 push 概念,多端不统一
|
||
*
|
||
* 方案:App 启动时生成一次 UUID v4,持久化到 storage:
|
||
* - 跨重启 / 跨账号 / 推送 SDK 升级 → 稳定不变
|
||
* - 卸载重装后才会变(storage 一起被清,业界无解)
|
||
*
|
||
* 自包含:第一次调用时自动 bootstrap,无需外部初始化。
|
||
* 三端统一(App / 小程序 / H5),不依赖 plus.* 等平台 API。
|
||
*/
|
||
|
||
const STORAGE_KEY = 'deviceFp'
|
||
|
||
/**
|
||
* 获取当前设备的稳定指纹;首次调用时自动生成并写入 storage。
|
||
* @returns {string} UUID v4 格式字符串
|
||
*/
|
||
export function getDeviceFingerprint() {
|
||
let fp = ''
|
||
try {
|
||
fp = uni.getStorageSync(STORAGE_KEY)
|
||
} catch (e) {
|
||
// storage 读取失败时降级:本次返回临时值,下次调用会重试
|
||
}
|
||
if (!fp) {
|
||
fp = generateUuidV4()
|
||
try {
|
||
uni.setStorageSync(STORAGE_KEY, fp)
|
||
} catch (e) {
|
||
// storage 写入失败不影响本次使用(仅会下次重新生成)
|
||
console.warn('[deviceFingerprint] setStorageSync failed', e)
|
||
}
|
||
}
|
||
return fp
|
||
}
|
||
|
||
/**
|
||
* 生成 RFC4122 v4 格式 UUID。
|
||
* 使用 Math.random()(uni-app 三端通用),不引入第三方库。
|
||
* 设备指纹场景对密码学强度无要求,唯一性即可。
|
||
*/
|
||
function generateUuidV4() {
|
||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||
const r = (Math.random() * 16) | 0
|
||
const v = c === 'x' ? r : (r & 0x3) | 0x8
|
||
return v.toString(16)
|
||
})
|
||
}
|