ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

QQ登录测试实战:从环境搭建到OAuth2.0自动化与弱网模拟

QQ登录测试实战:从环境搭建到OAuth2.0自动化与弱网模拟 简介QQLoginDemo是一份面向移动开发者的QQ第三方登录集成测试工程围绕QQ登录与分享功能展开帮助开发者解决从SDK接入、授权回调到用户信息获取的完整链路问题。资源共1985个文件压缩包约24.95MB以png图片、xml配置和json数据为主同时包含jar/class依赖库、aidl接口定义及gradle构建脚本兼顾界面资源、逻辑代码与工程配置便于直接导入分析与调试。已有576人浏览学习。项目清晰演示了安装SDK、配置URL Scheme、初始化SDK、实现登录逻辑、处理回调及验证并保存用户信息等典型步骤也覆盖了QQ空间分享和好友分享的调用方式。通过该工程可快速理解AppID/AppKey如何参与鉴权掌握access_token、open_id等关键数据的解析方法并复用现成的资源文件与配置模板有效缩短第三方登录功能的开发调试周期适合正在实现QQ互联能力或希望完善移动端登录体验的开发者参考。1. QQ登录测试在测什么一个“登录成功”背后有四道关卡“QQ登录测试”这个词测试工程师手里的含义比字面上宽得多。它不光是打开登录页、输账号密码、点一下登录而是一条从第三方应用跳到QQ授权页、用户确认授权、回调带回授权码、后端再换token并建立会话的完整链路。我见过不止一次线上事故在这条链路上翻车回调显示成功但会话没建起来授权码被重复消费把账号搞到风控弱网下用户点了登录半天没反应。这篇笔记按落地的顺序拆先搭测试环境再写可复跑的自动化脚本然后模拟弱网和中断最后是我踩过的五个典型坑和一条防重放的验证技巧。新手能跟着搭环境熟手可以对照检查自己的用例覆盖。2. 搭一套可复现的QQ登录测试环境测试应用、回调域名与账号隔离2.1 申请测试应用时最容易卡住的三个配置做QQ登录测试的第一步不是写用例是去QQ互联开放平台注册开发者并创建测试应用拿到app_id和app_secret。app_id会拼进授权请求的client_id参数里app_secret只出现在后端换token的请求中绝对不能落进前端代码或被抓包看到。很多团队第一步就卡在应用类型上网站应用要求回调地址是域名格式移动应用支持scheme跳转选错之后授权页形态、回调取值方式全都不一样。最稳妥的做法是明确当前被测入口是Web、H5还是App按入口固定应用类型别一个应用两头用。第二个卡点是回调地址。未审核的新应用对回调域名校验很严格最典型的报错就是“回调地址与注册域名不一致”。这里最常见的翻车是把端口写进回调地址比如http://127.0.0.1:8080/callback平台校验时直接拒绝。正确姿势是回调地址只填域名不带端口本地调试用hosts映射加转发实现具体方案下一节展开。第三个卡点是接口权限。新应用默认的get_user_info等接口可能处于受限状态token换成功了但拉用户资料返回错误码测试很容易误判成“登录失败”。进开发环境前先把“获取用户信息”这类常用接口权限在开发设置里逐项申请好省得后面排错排半天。配置项常见错误推荐做法应用类型网站和移动应用混用按入口固定H5登录用网站应用回调地址带端口或带路径纯域名本地用hosts转发接口权限未申请就开测先配好get_user_info再跑用例2.2 回调地址的本地调试改hosts还是改重定向本地调QQ登录最烦的就是“平台只认域名不认端口”。我常用的方案是给本机配一个假域名让授权流程完整走真实链路。先在hosts文件里加映射macOS和Linux编辑/etc/hostsWindows编辑C:\Windows\System32\drivers\etc\hosts加一行# 把测试域名指向本机之后授权回调会落到本地 127.0.0.1 lite.qq.test然后在开放平台把回调域名配置成lite.qq.test本机再起一个nginx或轻量反代监听80/443端口把该域名的流量转发到应用实际监听的端口server { listen 80; server_name lite.qq.test; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; } }这个方案能成立的关键是QQ授权服务器校验的是回调域名hosts让本机把这个域名解析到127.0.0.1应用监听8080nginx做转发于是整个授权链路从URL到流量全是真实的。相比用Fiddler做Map Remote改写重定向改hosts在网络层解决域名解析对QQ互联这类严格校验域名的平台更可靠。移动端调试时手机也要改hostsAndroid端需要root或同网段代理iOS麻烦一些如果开发机是Mac可以起个本地HTTP代理把流量导过去。需要留意的是QQ授权页默认弹窗或iframe嵌入跨域限制比传统整页跳转严格。测试时要把浏览器“允许弹窗”打开否则授权页被浏览器拦截表现就是“点了QQ登录按钮完全没反应”。2.3 测试账号准备与数据隔离别拿生产QQ号跑用例登录测试最忌讳拿自己常用QQ去跑不只是隐私问题授权记录、设备指纹、风控特征全会串到线上账号上真出了线上问题都没法解释。我一般准备三类测试账号首次授权的新账号验证从零到建会话的完整流程已经授权过一次的账号验证再次登录时是否走静默或免授权分支拒绝过授权的账号验证回调带error的失败分支。有条件的团队再备一个异常账号比如被冻结或长期异常登录的给安全测试用。账号数据单独维护一张测试数据表不混在生产用户表里字段示例值说明账号标识qq_test_01测试昵称日志里好识别授权状态首次/已授权/拒绝过决定跑哪个分支归属应用测试应用App ID防止串到生产应用最近授权时间2025-06-01 10:00控制频控触发注意一个底层事实授权记录在服务端是按client_id隔离的用测试应用的app_id产生的授权不会污染用户账号在正式应用里的授权列表反之亦然。所以测试账号和生产账号分开同时也是在用隔离机制保护生产数据。另外同一账号不要高频重复扫码授权自动化脚本循环扫码几十次很容易触发频控真被拦了要看具体错误码区分token失败、接口权限不可用和风控拦截三类情况别笼统叫“登录失败”。3. 核心流程自动化用Playwright把授权码登录做成可复跑的自动化冒烟脚本3.1 QQ OAuth2.0授权码流程的测试要点拆解QQ互联新版登录走的是OAuth2.0授权码模式链路拆成四步第一步前端发起授权请求把用户带到graph.qq.com的authorize地址第二步用户在QQ侧登录并确认授权第三步QQ把浏览器重定向回应用配置的回调地址URL里带上code和state第四步后端拿code去token接口换access_token再拉用户信息建立登录会话。测试断言要跟这四步对应不能只看到“跳回应用首页”就宣布通过。我见过不少自动化测试方案跑到第一步结束就停了那只验证了跳转参数真正决定登录成败的换token和建会话环节根本没测到。四个环节的断言重点如下环节关键参数主要断言发起授权client_id、redirect_uri、state参数完整state是随机值且后端可校验用户授权无区分确认授权/拒绝授权两个分支回调code、statecode存在state与发起时一致换tokencode、app_secret返回token重复兑换被拒绝3.2 半自动脚本从应用页到授权页再到回调捕获真实授权流程绕不开扫码纯无头自动化在授权页会被验证码和风控卡死。实际项目里最实用的是一段半自动脚本脚本自动走到QQ授权页人工扫码脚本捕获回调并断言关键参数。下面这版用Playwright既能在本地人工值守时跑也能作为发布前的冒烟步骤。# qq_login_smoke.py # 作用跑通“应用页 → QQ授权页 → 手动扫码 → 回调带回code”的前端半自动链路 import re from playwright.sync_api import sync_playwright REDIRECT_URI http://lite.qq.test/callback # 必须与平台配置完全一致 def extract_param(url, key): 从回调URL里提取query参数注意兼容#号后面的部分 r re.search(rf[?]{key}([^]), url) return r.group(1) if r else None with sync_playwright() as p: browser p.chromium.launch(headlessFalse) # 半自动必须能看到页面配合扫码 page browser.new_page() page.goto(http://lite.qq.test/) # 被测应用首页 page.click(button:has-text(QQ登录)) # 按应用自己的DOM选择器调整 page.wait_for_url(re.compile(rgraph\.qq\.com/oauth2\.0/authorize), timeout15000) print(已到达QQ授权页请手动完成扫码授权限时120秒) # 扫码完成后QQ会重定向回回调地址等待这个跳转 page.wait_for_url(re.compile(re.escape(REDIRECT_URI) r.*), timeout120000) url page.url code extract_param(url, code) state extract_param(url, state) assert code, 回调URL里没有code授权流程未真正完成 print(回调成功code前8位, code[:8], state, state)headlessFalse和120秒超时是特意设计的QQ扫码登录需要人眼参与不能无头化120秒是给人工操作留的余量实际扫码通常十几秒就够。wait_for_url接收正则两个正则都做了转义其中REDIRECT_URI里的小数点用re.escape包起来否则会被当通配符回调域名一长串都可能误匹配。这段脚本跑完后把打印出的code交接给后端token脚本用注意code是一次性的中间间隔别拖太久。3.3 后端换token用Python直连token接口断言登录态前端拿到code不等于登录成功后端拿code换token才是真正的关口。我习惯单独写一段接口测试脚本不经过浏览器把code作为入参直接打token接口# qq_token_test.py # 作用用单个code换取access_token并核对用户信息接口 import requests APP_ID 101000000 # 替换成测试应用的app_id APP_SECRET replace_me # 替换成测试应用的app_secret REDIRECT_URI http://lite.qq.test/callback def exchange_token(code): resp requests.post( https://graph.qq.com/oauth2.0/token, data{ grant_type: authorization_code, client_id: APP_ID, client_secret: APP_SECRET, code: code, redirect_uri: REDIRECT_URI, }, timeout10, ) # QQ互联的token接口历史上返回的是form编码文本不是JSON先看原始文本 if resp.status_code 200 and access_token in resp.text: kv dict(x.split(, 1) for x in resp.text.split()) return kv.get(access_token) print(token接口异常status:, resp.status_code, resp.text[:300]) return None def fetch_user_info(access_token): resp requests.get( https://graph.qq.com/oauth2.0/me, params{access_token: access_token}, timeout10, ) # 该接口返回带回调函数包裹的文本按实际格式解析不要硬写成resp.json() return resp.text跑这段脚本时把3.2打印的code在几十秒内喂进来。code过期后token接口会返回明确的过期错误这本身就是一条有效用例别当成脚本bug。token接口返回格式随平台策略可能变化有人把它当JSON解析翻过车我第一次跑的时候也踩了——正确做法是先print原始文本看清是form编码还是JSON再写解析逻辑。判断登录成功不能只看有没有token要接着调get_user_info用返回的昵称头像字段和后端库里的会话记录做断言。3.4 CI里跑QQ登录自动化的可行方案真实授权码在CI里跑不通因为每次都要扫码。这里给一个分层落地的思路把QQ登录自动化拆成前端和后端两层前端层断言授权跳转参数后端层用测试环境签发的token跑接口用例授权码换token的完整链路留在发布前人工冒烟。CI里的token由一个人工值守的定时任务维护过期了自动报黄提醒而不是让CI卡在扫码上。这样做的考虑是QQ扫码授权本质是人为操作强行自动化成本极高收益却很低——真正容易回归的是参数拼接和token解析这两块恰恰能用脚本稳定覆盖。Appium这类移动端自动化在QQ登录场景里也适用同一个思路原生入口侧可以自动化授权页一旦进入WebView扫码环节仍然要人参与别高估端到端自动化的覆盖面。4. 弱网与中断测试用Fiddler模拟慢速回调和授权中断4.1 Fiddler弱网参数设置三个档位覆盖主要场景QQ登录是重度依赖跳转的流程弱网影响比普通接口明显得多授权页加载慢、回调包丢失、前端超时判断不准全都在这里暴露。Fiddler做弱网的基本方式是改CustomRules.js里的两个钩子按域名区分处理逻辑// CustomRules.js 中追加只对QQ授权相关域名生效 // 轻弱网1秒延迟带宽不限制模拟4G不稳定 if (oSession.HostnameIs(graph.qq.com)) { oSession[response-trickle-delay] 1000; } // 重弱网3秒延迟请求体按极低速率发送模拟电梯/地铁弱信号 if (oSession.fullUrl.indexOf(graph.qq.com) -1) { oSession[request-trickle-delay] 1; oSession[response-trickle-delay] 3000; }request-trickle-delay设置为1时Fiddler按每字节级速度发送请求体等效极低上行带宽response-trickle-delay控制响应下发速度只调它就能模拟“服务端返回慢”这是测回调超时最直接的手段。除了改脚本Fiddler菜单里的Rules→Performance→Simulate Modem Speeds是内置的调制解调器档位但那个档位对登录场景过猛授权页经常直接加载不出来不太适合做梯度测试。我实测下来常用三个自定义档位档位响应延迟带宽特征适用场景轻微200ms不限制4G边缘信号中等1.5s100KB/s级别地铁、电梯极端3s极低且丢包弱信号、跨省漫游丢包在Fiddler里改起来没有带宽直观可以配合系统级的网络限制工具做注入。对QQ登录来说丢包场景最关键的观察点是授权页加载失败后应用有没有明确报错还是让用户一直停在白屏。4.2 回调被掐断后的前后端表现Fiddler断点与Abort弱网下最常见的故障是“用户扫码成功但回调请求丢了”。测试时不能只观察页面要分别盯前端和后端的表现。前端侧应用应该从“登录中”状态兜底到失败提示或重试按钮超时时间一般设在15到30秒如果前端没有超时机制用户会一直挂在loading上这是QQ登录体验里最伤的一点。后端侧回调没删到应用服务器收不到codetoken接口不会被调用特征就是后端完全没有这次回调和授权日志。用Fiddler断点模拟回调被掐断的步骤是启动Fiddler打开应用登录页完成扫码在回调请求出现时立刻按F12打断点把请求卡在网络层。然后分两种验证放行并等30秒以上再恢复观察前端超时提示或者直接在断点处Abort模拟连接被重置。Abort是模拟回调丢失最快的方式重点检查三件事前端是否显示明确错误而不是一直loading后端是否留下异常日志有没有重试机制用户重新点击“QQ登录”时state是否重新生成这三条里最容易被忽视的是最后一条。如果回调丢失后再次登录仍复用旧state登录请求就是可重放的如果每次点击都重新生成state说明防重放设计是到位的。弱网测试让人感觉像玄学就是因为这些细节不在页面上显性可见要结合抓包和日志一起看。4.3 授权码过期与token过期容易被误判的两种失败弱网往往伴随token获取慢这里有个真实会发生的边界授权页打开得很慢用户等了很久才扫码扫码后回调到达但授权码已经临近有效期后端换token时直接提示过期。这类失败表面是弱网导致的实际是授权码生命周期和网络延迟叠加出来的排查时很容易绕圈子。测试方法是在扫码完成后用Fiddler断点人为卡住回调30秒以上再放行观察后端token接口的返回。如果返回明确过期错误码说明前后端对超时的处理是对的不少应用在这里只给一个笼统报错用户完全不知道是重新授权还是再等一次。第二个容易漏的场景是access_token过期测试拿到token后把系统时间往后拨一天再调用户信息接口看是否返回token失效。改系统时间会影响TLS证书校验和本地缓存谨慎操作更稳妥的做法是把后端token有效期参数临时调短比如设成60秒等它自然过期后跑接口用例跑完再调回正常值。5. 五个QQ登录测试的典型坑现象、原因、解决5.1 授权页报“回调地址错误”应用登录按钮像失效现象点击QQ登录授权页或回调页提示“QQ登录失败”或100010类错误看起来像登录功能整个挂掉了。 原因回调地址和开放平台配置不一致。最常见的是本地调试把端口写进了回调地址或者HTTP和HTTPS混用平台校验时直接拒绝。 解决回调地址统一用纯域名不带端口本地用hosts加nginx转发方法在第2.2节。如果仍然报错把授权请求里的redirect_uri原样打印出来和平台配置逐字符对比注意URL编码后斜杠、冒号有没有被转义成%2F、%3A。这条排查路径百发百中。5.2 回调里的state参数没校验测试环境被刷出脏数据现象抓包发现把上一条的code、state直接拼到URL里重放应用居然也走完了登录流程后端多出一堆无来源的登录记录。 原因后端只校验了code有效性没校验state是否和本次发起的请求一致。state的角色是防CSRF和防重放不校验等于把登录入口裸奔。 解决后端在发起授权时把state存到session或redis回调时比对一致才放行。测试用例里专门构造一个错误state的请求断言它被拒绝。生成state时用随机串加签名回调时先验签名再比库双重校验。5.3 同一授权码被换两次token测试QQ号被风控现象弱网下用户点了两次登录后端把同一个code兑换了两次第二次返回错误。随后用同一测试QQ号再授权直接被拦截。 原因授权码是一次性的后端没有对code做幂等处理重试请求重复触发了兑换。 解决后端加幂等标记对code先记录后消费已消费的code返回明确错误码测试脚本里加一条“重复兑换同一code”的用例专门验证幂等。账号被风控不是代码问题而是操作问题测试时别把同一账号授权频率调太高换个间隔再继续。5.4 真机扫码秒成功自动化环境却一直授权失败现象同一测试应用手机扫码秒过自动化脚本或无头浏览器环境怎么调都授权失败。 原因QQ对异常设备和异常IP有风控。自动化脚本用无头浏览器、数据中心IP去访问授权页命中风控的概率远高于真机。 解决改用真实设备或带图形界面的桌面浏览器跑扫码流程出口IP用常用网络不要在短时间内对同一测试号授权几十次。风控命中的判断标准是错误码特征和token接口返回不同别把风控误判成接口bug。这属于QQ登录测试里的环境因素只能靠贴近真实用户频率来规避。5.5 只测了授权成功没测用户拒绝授权现象用户点授权页的“取消”或拒绝按钮应用logo页闪了一下又回到登录页没有错误提示没有后续引导。 原因拒绝授权时QQ回调的URL带的是error字段而不是code后端代码没写error分支前端也没做失败态。 解决用例里加“拒绝授权”分支断言回调URL带erroraccess_denied时应用页能提示“已取消授权”而不是静默跳回。自动化做法是脚本里点授权页的取消按钮不点确认按钮。这条用例成本最低最容易漏。6. 留一个防重放技巧给state加签名后做回归验证前面几个坑反复提到state校验这里给一个能直接抄的签名实现。state的生成端和校验端约定同一个secret生成时把时间戳、用户标识和随机数拼起来做HMAC签名回调时重新计算并比对# state_signer.py # 作用生成带签名的state并在回调时验证完整性防重放 import hashlib import hmac import time import secrets def make_state(secret: str, uid: str) - str: ts str(int(time.time())) nonce secrets.token_hex(8) raw f{ts}.{uid}.{nonce} sig hmac.new(secret.encode(), raw.encode(), hashlib.sha256).hexdigest()[:16] return f{raw}.{sig} def verify_state(secret: str, state: str) - bool: parts state.split(.) if len(parts) ! 4: return False ts, uid, nonce, sig parts # 时间窗校验超过5分钟的state直接拒绝防重放 if abs(int(time.time()) - int(ts)) 300: return False expect hmac.new(secret.encode(), f{ts}.{uid}.{nonce}.encode(), hashlib.sha256).hexdigest()[:16] return hmac.compare_digest(sig, expect)使用时机是发起授权时调用make_state生成state回调校验时调用verify_state。回归脚本里分别喂三组输入——正确的state、篡改过签名的state、超过5分钟的旧state断言只有第一组通过。这是把第5.2节的坑变成自动化用例的最直接方式比每次手工拼参数踏實得多。我习惯把这段逻辑打进测试公共包里每个接入QQ登录的项目回归时都带上希望帮到你。本文还有配套的精品资源点击获取
返回列表