在 React 网页项目(Web)中,我们无法获取到如IMEI、MAC地址或系统序列号这类硬件级别的绝对唯一码。这是浏览器隐私安全策略决定的,目的是防止用户被跨站点追踪。
不过,我们可以通过生成设备指纹或自行创建并存储UUID这两种主流方案,来为每个访问的设备生成一个稳定且可用于身份识别的唯一标识。
| 方案 | 实现原理 | 唯一性 | 持久性 | 推荐指数 |
|---|---|---|---|---|
| 设备指纹 | 收集浏览器及硬件信息(如Canvas、UserAgent、屏幕分辨率等)进行哈希计算,生成独一无二的"指纹" 。 | 高(不同设备指纹碰撞概率极低) | 较高(浏览器升级或硬件变更可能改变) | ⭐⭐⭐⭐⭐ (首选) |
| 本地生成UUID | 在浏览器本地生成一个全局唯一标识符(UUID),并存储在 localStorage 中 。 | 极高(由算法保证) | 高(用户不清除浏览器数据就不会变) | ⭐⭐⭐⭐ (备选) |
它会收集浏览器的各种属性(如用户代理、屏幕分辨率、Canvas 指纹、WebGL 信息、已安装字体等)来生成一个高度唯一的访客标识符 。与你自己生成并存储 UUID 的方案相比,它生成的指纹在无痕模式下仍然有效,即使用户清除了浏览器数据,只要硬件和软件环境没大变,指纹也能保持稳定 。
代码使用:
npm i @fingerprintjs/fingerprintjs
# 或
yarn add @fingerprintjs/fingerprintjs
// useUserFingerprint.ts
import { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { setFingerprint } from '@/store/slices/fingerprintSlice';
import type { AppDispatch } from '@/store';
export default function useUserFingerprint() {
const dispatch = useDispatch<AppDispatch>();
const [loading, setLoading] = useState(true);
useEffect(() => {
let mounted = true;
(async () => {
try {
// 动态导入以减少首包体积
const mod = await import('@fingerprintjs/fingerprintjs');
const FingerprintJS = (mod && (mod.default ?? mod)) as any;
if (!FingerprintJS) return;
const fp = await FingerprintJS.load();
const result = await fp.get();
const visitorId = result?.visitorId;
if (mounted) {
dispatch(setFingerprint(visitorId));
}
} catch {
// 忽略指纹获取错误
} finally {
if (mounted) setLoading(false);
}
})();
return () => {
mounted = false;
};
}, [dispatch]);
return { loading };
}
// @/store/slices/fingerprintSlice.ts
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
import type { FingerprintState } from '@/types/store/fingerprint';
const initialState: FingerprintState = {
fingerprint: undefined,
};
export const fingerprintSlice = createSlice({
name: 'fingerprint',
initialState,
reducers: {
setFingerprint: (state, action: PayloadAction<string | undefined>) => {
state.fingerprint = action.payload;
},
},
});
export const { setFingerprint } = fingerprintSlice.actions;
export default fingerprintSlice.reducer;
注意事项:
这是最直接、最传统的方法。如果用户不清理浏览器缓存,这个ID将永久有效 。
1/ 安装uuid库:
npm i uuid
# 或
yarn add uuid
2/ 封装工具函数:
// utils/deviceId.js
import { v4 as uuidv4 } from "uuid";
// 定义存储在localStorage中的键名
const DEVICE_ID_KEY = "my_web_app_device_id";
export const getDeviceId = () => {
// 尝试从localStorage读取
let deviceId = localStorage.getItem(DEVICE_ID_KEY);
// 如果没有,则生成一个新的并保存
if (!deviceId) {
deviceId = uuidv4();
localStorage.setItem(DEVICE_ID_KEY, deviceId);
}
return deviceId;
};
3/ 在React组件中使用:
import React, { useEffect } from 'react';
import { getDeviceId } from './utils/deviceId';
function App() {
useEffect(() => {
const deviceId = getDeviceId();
console.log('当前设备ID:', deviceId);
// 你可以将这个ID附加到API请求中,用于识别设备
}, []);
return (
// ... 你的组件内容
);
}
export default App;