You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django捕获客户端设备信息:跨设备登录触发功能需求

解决Django中设备唯一识别的问题

核心思路

要区分同系统、同浏览器的不同设备,不能仅依赖django-user-agents提取的基础信息,需要结合多维度客户端标识生成唯一设备指纹,同时兼顾隐私合规性。

可行实现方案

1. 组合多维度标识生成设备指纹

收集以下客户端信息,通过哈希算法生成唯一指纹(维度越多,区分度越高):

  • 完整的User-Agent字符串(不要仅提取浏览器/系统家族,保留原始细节)
  • 屏幕参数:分辨率、设备像素比(window.screen.width/height/devicePixelRatio)
  • 时区偏移(new Date().getTimezoneOffset())
  • 浏览器语言列表(navigator.language + navigator.languages)
  • 硬件相关信息:CPU核心数、设备内存(navigator.hardwareConcurrency/deviceMemory)
  • 可选:Canvas/WebGL指纹(不同GPU渲染的细微差异,通过绘制内容生成哈希)

2. Django后端实现步骤

  • 前端在用户登录时,通过JavaScript收集上述信息,拼接后用SHA-256哈希,将结果传给后端。
  • 后端新增UserDevice模型,存储用户与设备指纹的关联关系,包含user、fingerprint、last_login等字段。
  • 每次登录时对比当前指纹与用户已存储的指纹:
    • 无匹配时触发指定功能(如邮件验证、二次身份验证),同时新增设备记录。
    • 有匹配时更新该设备的最后登录时间。

3. 代码示例

前端JS(生成指纹)

async function generateDeviceFingerprint() {
  // 收集基础标识
  const userAgent = navigator.userAgent;
  const screenInfo = `${window.screen.width}x${window.screen.height}x${window.devicePixelRatio}`;
  const timezone = new Date().getTimezoneOffset();
  const languages = navigator.languages.join(',');
  const hardwareInfo = `${navigator.hardwareConcurrency}-${navigator.deviceMemory}`;
  
  // 可选Canvas指纹
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  ctx.fillText('device-fingerprint', 0, 0);
  const canvasHash = await crypto.subtle.digest('SHA-256', ctx.getImageData(0,0,1,1).data);
  const canvasHex = Array.from(new Uint8Array(canvasHash)).map(b => b.toString(16).padStart(2, '0')).join('');
  
  // 拼接生成唯一字符串后哈希
  const rawString = `${userAgent}|${screenInfo}|${timezone}|${languages}|${hardwareInfo}|${canvasHex}`;
  const hashBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(rawString));
  return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('');
}

// 登录时传递指纹
document.getElementById('login-form').addEventListener('submit', async (e) => {
  e.preventDefault();
  const fingerprint = await generateDeviceFingerprint();
  const formData = new FormData(e.target);
  formData.append('device_fingerprint', fingerprint);
  // 提交表单请求...
});

Django后端模型与登录逻辑

# models.py
from django.db import models
from django.contrib.auth.models import User

class UserDevice(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='devices')
    fingerprint = models.CharField(max_length=64, unique=True)
    last_login = models.DateTimeField(auto_now=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = '用户设备'
        verbose_name_plural = '用户设备'

# views.py 登录验证部分
from django.contrib.auth import authenticate, login
from django.http import JsonResponse
from .models import UserDevice

def login_view(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        fingerprint = request.POST.get('device_fingerprint')
        
        user = authenticate(request, username=username, password=password)
        if user:
            login(request, user)
            # 检查设备指纹
            existing_device = UserDevice.objects.filter(user=user, fingerprint=fingerprint).exists()
            if not existing_device:
                # 触发指定功能(示例:发送验证邮件)
                send_device_verification_email(user)
                # 新增设备记录
                UserDevice.objects.create(user=user, fingerprint=fingerprint)
            return JsonResponse({'status': 'success'})
        else:
            return JsonResponse({'status': 'error', 'message': '用户名或密码错误'})

4. 注意事项

  • 隐私合规:确保收集的信息符合GDPR、CCPA等法规,避免收集敏感数据,同时告知用户设备指纹的用途。
  • 指纹稳定性:优先选择相对稳定的维度(如User-Agent、屏幕参数),避免因浏览器更新导致指纹频繁变化。
  • 降级方案:若用户禁用JavaScript,可降级使用User-Agent+IP组合(注意同一局域网设备IP可能重复),同时提示用户开启JS以提升安全体验。

内容的提问来源于stack exchange,提问作者Anant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:12:19