扫码登录核心流程为:用户访问登录页→后端生成唯一login_token存cache→前端拼二维码链接→客户端扫码请求回调→后端校验并绑定用户;需用cache而非session存token,确保域名外网可达、路由正确、缓存驱动一致、跨域配置完备。
扫码登录的核心流程在ThinkPHP里怎么串起来
ThinkPHP本身不内置扫码登录功能,必须自己搭三端联动:前端生成二维码、后端维护登录状态、客户端扫码后回传凭证。关键不是“用哪个扩展”,而是把
、
和临时票据(如
)对上号。
典型做法是:用户访问登录页 → 后端生成唯一
并存入
(带过期时间,比如 5 分钟)→ 前端用该 token 拼出二维码链接(如
)→ 手机端扫码后请求该地址 → 后端校验 token 有效性,绑定用户身份,写入登录态。
别用
存 token,因为扫码回调请求和网页轮询请求可能跨域或无 Cookie,必须依赖
或数据库
必须一次性使用:校验成功后立即
或
,防止重放
前端轮询接口(如
)返回格式建议统一为 JSON:
生成二维码时要注意哪些参数和路径问题
ThinkPHP 8.x 可直接用
扩展(注意不是官方包),但重点不在“怎么画图”,而在于二维码里塞的链接是否可被手机正确识别、跳转、且服务端能接住。
示例中常见错误是生成了
—— 手机扫了打不开。必须用外网可访问域名,且路径要走 ThinkPHP 路由(别写成物理路径)。
立即学习
“
PHP免费学习笔记(深入)
”;
生成前先确认当前环境域名:用
拼接,而不是硬编码
二维码内容推荐用完整 URL,如
,避免客户端解析歧义
如果用
,注意返回的是 base64 字符串,前端要写成
,别漏了前缀
别在控制器里直接 echo 图片二进制——ThinkPHP 默认输出是文本,要用
扫码回调接口为什么总报 404 或 token 无效
最常踩的坑是路由没配对、缓存驱动不一致、或时间不同步。比如开发用
缓存,生产用
,结果本地测试 OK,上线就
返回 null。
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
另一个高频问题是:手机扫码发起的请求默认不带 session cookie,所以不能依赖
来判断是否已登录,一切状态都要从
或数据库查。
检查路由是否启用
(如果前端在不同域名调
)
回调接口(如
)必须允许 POST,且接收方式用
,不是
或
用
先判断存在性,再
取值,避免空值误判为已登录
如果用了多级缓存(如先查 Redis 再查 File),确保所有环境缓存配置一致,尤其
驱动名
用户登录态怎么安全地透传给原网页
扫码成功后,不能简单跳转
就完事。原网页还在轮询,得让它立刻知道“已登录”,并拿到用户信息。常见做法是轮询接口返回
后,前端用该 ID 主动发一次
换取 session 和 cookie。
这个换态接口必须做二次校验:比如检查
对应的账号是否启用、是否被禁用、上次登录 IP 是否异常等,不能只认 ID。
换态成功后,务必调用
,并确保
已触发(ThinkPHP 通常自动处理)
别把
直接当登录凭证返回给前端,轮询响应里只返回必要字段,敏感信息如手机号、token 由后端内部处理
如果项目启用了
或
,确认 HTTPS 环境下 cookie 能正常写入,否则登录态看似成功实则无效
整个链路里最容易被忽略的是缓存失效策略和跨域请求头。哪怕二维码生成和扫码都对了,只要轮询响应没带
,前端就收不到 success 状态,用户永远卡在“请扫码”页面。
sessioncacheqrcode_tokenlogin_tokencache/auth/scan?token=abc123sessioncachelogin_tokencache::pull()delete()/auth/check?token=abc123{"status": "waiting"|"success"|"expired", "user_id": 123}think-qrcodehttp://localhost/auth/scan?token=xxxrequest()->domain()https://your.com/auth/scan?token=7f9a2bQrCode::size(300)->generate($url)response()->contentType('image/png')->content($pngData)FileRediscache::get($token)$this->request->session()cacheallow_cross_domain/auth/checkAuthController::scan()$this->request->param('token')input()get()cache::has($token)cache::get($token)default/indexuser_id/auth/login_by_token?user_id=123user_idsession('user', $userInfo)session_start()user_idcookie_securecookie_httponlyAccess-Control-Allow-Origin