如何在Django后端检测用户是否使用PWA/TWA访问站点
Django 后端检测 PWA/TWA 访问的实现方案
核心逻辑说明
前端的三类判断规则可以对应到后端请求特征逐一校验,相比前端判断安全性更高,难以被用户随意篡改。
具体实现步骤
1. 校验TWA访问(对应前端document.referrer.includes('android-app://')逻辑)
直接读取请求头的Referer字段,如果值包含android-app://前缀即可判定为TWA访问。
对应Django代码:
def is_twa_request(request): referer = request.META.get('HTTP_REFERER', '') return 'android-app://' in referer
2. 校验PWA standalone模式访问
分两类场景实现校验:
场景A:通过客户端提示头(Client Hint)检测
现代主流浏览器在PWA以standalone模式运行时,会发送Sec-CH-Display-Mode请求头,值为standalone。要获取这个头,需要先在Django的响应头里添加Accept-CH: Sec-CH-Display-Mode,告知浏览器发送该提示头。
可以通过自定义中间件统一添加响应头:
# 自定义中间件,添加Accept-CH头 class PWAClientHintMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) response["Accept-CH"] = "Sec-CH-Display-Mode" return response
将中间件添加到settings.py的MIDDLEWARE列表后,即可通过请求头做判断:
def is_pwa_standalone(request): # 检测标准Sec-CH-Display-Mode头 display_mode = request.META.get('HTTP_SEC_CH_DISPLAY_MODE', '') if display_mode == 'standalone': return True # 兼容iOS端PWA的特殊特征判定 user_agent = request.META.get('HTTP_USER_AGENT', '') if 'iPhone' in user_agent or 'iPad' in user_agent: # iOS standalone模式下User-Agent不会包含Safari版本标识 if 'Safari/' not in user_agent and 'Version/' not in user_agent: return True return False
场景B:start_url标记+签名校验(防篡改等级最高)
在PWA的manifest.json中配置start_url时,添加带动态签名的查询参数:
{ "start_url": "/?pwa_launch=1&sign=服务端动态生成的签名值" }
后端返回manifest时动态生成签名,校验时先验证sign合法性,再判断pwa_launch参数是否存在,完全避免前端伪造请求特征。
3. 综合判定函数
整合两类逻辑即可得到和前端判断等价、但安全性更高的检测结果:
def is_pwa_or_twa(request): return is_twa_request(request) or is_pwa_standalone(request)
注意事项
- 如果需要更高安全级别,可以配合前端将PWA运行状态加密后通过自定义请求头发送,后端解密后二次校验。
Sec-CH-Display-Mode头仅在HTTPS环境下生效,本地HTTP开发环境可能无法获取。
内容的提问来源于stack exchange,提问作者mascDriver
相关产品推荐
相关产品推荐

