thinkphp微信网页授权必须手动实现oauth2.0三步:控制器用response()->redirect()拼接含urlencode(redirect_uri)、正确scope和state的授权url;回调中校验state后立即换token;再用同一响应中的access_token和openid调userinfo接口,全程严格校验errcode。

ThinkPHP 没有封装微信网页授权的“一键登录”逻辑,必须手动走完整 OAuth2.0 三步:拼授权 URL → 处理回调拿到 code → 用 code 换 access_token 和 openid → 再调 userinfo 接口拉信息。跳过任何一环或混用参数都会失败。
怎么拼出正确的微信授权跳转链接
入口不能靠前端 JS 跳,必须由 ThinkPHP 控制器用 response()->redirect() 发起 302,否则 state 易丢失、redirect_uri 编码易出错。
-
redirect_uri必须和公众号后台「网页授权获取用户基本信息」里填的**域名完全一致**(含协议、端口、路径、结尾斜杠),例如后台填了http://localhost:8000/callback/wechat,那就得一字不差 -
scope选snsapi_userinfo才能拿昵称头像;选snsapi_base只静默返回openid,且用户未关注公众号时会报错 -
state建议存进 session 或加密字符串,回调时比对,防 CSRF;别硬写死成123这类常量 - URL 中所有参数都要
urlencode(),尤其是redirect_uri,漏掉会导致redirect_uri mismatch
示例代码片段:
public function login()
{
$appid = config('wechat.app_id');
$redirect_uri = urlencode('http://localhost:8000/callback/wechat');
$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appid}&redirect_uri={$redirect_uri}&response_type=code&scope=snsapi_userinfo&state=" . md5(session_id()) . "#wechat_redirect";
return response()->redirect($url);
}
回调方法里如何安全处理 code 并换 token
收到 code 后必须立刻发起请求换 token,不能缓存、不能重放、不能跨请求复用 —— code 5 分钟失效且仅能使用一次。
- 先校验
state是否匹配 session 中存的值,不匹配直接拒绝,防止伪造回调 - 换 token 的地址是
https://api.weixin.qq.com/sns/oauth2/access_token,不是管理接口的通用 token 地址;参数是appid、secret、code、grant_type=authorization_code - 微信返回的是 JSON 字符串,必须用
json_decode($res, true)解析,否则数组键名大小写或类型错误会导致取不到access_token - 别把
access_token存数据库或长期缓存 —— 它是网页授权专用 token,有效期 2 小时,且不能调用用户管理类接口
常见错误:{"errcode":40029,"errmsg":"invalid code"},基本就是 code 过期、重复使用、或 appid/secret 配错了。
公众号运营:文章发布至草稿、样式封面、评论与用户管理、数据统计等。用户要求将 Markdown 发送到公众号草稿、查看阅读量统计或类似后台操作时,使用本技能。
拉 userinfo 时为什么总报 invalid openid
这个错误几乎全是参数错配导致的,不是网络或权限问题。
-
access_token和openid必须来自**同一轮/sns/oauth2/access_token响应**,不能拿 A 用户的access_token+ B 用户的openid - 调
https://api.weixin.qq.com/sns/userinfo时,access_token和openid都要 URL 编码,尤其openid含字母数字,不编码可能被截断 - 确认用户已关注公众号 ——
snsapi_userinfo要求用户关注后才能成功返回信息;未关注时只能用snsapi_base拿openid,再引导关注 - 别漏掉
lang=zh_CN参数,虽然不影响字段返回,但微信文档明确要求带上
正确请求示例:
$userinfo_url = "https://api.weixin.qq.com/sns/userinfo?access_token=" . urlencode($token_data['access_token']) . "&openid=" . urlencode($token_data['openid']) . "&lang=zh_CN";
为什么不能在中间件或模型里做微信登录逻辑
OAuth2.0 是强上下文流程:需要实时响应重定向、即时消费 code、依赖当前用户 session 和 request query 参数。中间件无法控制跳转时机,模型没有 HTTP 上下文,强行塞进去只会导致 code 丢失、state 校验失败、或 token 换取后无法回传给前端。
- 入口跳转和回调处理都必须放在控制器方法里,且建议拆成两个独立 action(如
login和callback) - 别试图在
__construct或_initialize里自动跳转 —— ThinkPHP 的生命周期里,这些方法执行时可能已输出 header,导致重定向失败 - 回调方法里拿到用户信息后,该登录就调
Auth::login(),该注册就写入用户表,别留到视图层再处理
最易被忽略的一点:整个流程中所有微信接口返回的 JSON,都必须检查 errcode 字段。微信不按 HTTP 状态码报错,200 OK 响应体里照样可能是 {"errcode":40003,"errmsg":"invalid openid"} —— 不显式判断就等于裸奔。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










