Iris框架不封装OAuth2逻辑,微信登录需用golang.org/x/oauth2手动实现:严格匹配四个endpoint、redirect_uri需URL编码且必须HTTPS;state须存session并恒定时间比对;Exchange前需确保body未被读空;/sns/userinfo响应含BOM需手动去除。

iris 框架本身不封装 OAuth2 逻辑,微信登录必须靠 golang.org/x/oauth2 拼装流程,再用 iris 的路由和中间件兜住上下文——错一个字段、漏一次校验、少一个斜杠,就卡在白屏或 invalid_request。
微信 OAuth2 四个必填 endpoint 和 redirect_uri 编码规则
微信开放平台对回调地址(redirect_uri)和授权端点要求比 GitHub/Google 更严:
- Endpoint.AuthURL 必须是 https://open.weixin.qq.com/connect/oauth2/authorize
- Endpoint.TokenURL 必须是 https://api.weixin.qq.com/sns/oauth2/access_token
- RedirectURL 不仅要和后台注册值**逐字节一致**,还必须在拼进 AuthCodeURL 前对路径部分做 URL 编码(如 /auth/callback → %2Fauth%2Fcallback)
- 微信不认 http://,本地调试也得配 HTTPS(可用 mkcert 生成 localhost 证书),否则直接拒绝
config := &oauth2.Config{
ClientID: os.Getenv("WECHAT_APPID"),
ClientSecret: os.Getenv("WECHAT_APPSECRET"),
RedirectURL: "https://localhost:8080/auth/callback", // 注意:这是你代码里写的值,不是传给 AuthCodeURL 的
Scopes: []string{"snsapi_userinfo"},
Endpoint: oauth2.Endpoint{
AuthURL: "https://open.weixin.qq.com/connect/oauth2/authorize",
TokenURL: "https://api.weixin.qq.com/sns/oauth2/access_token",
},
}
生成跳转链接时手动编码:url.QueryEscape(config.RedirectURL),不能直接把 config.RedirectURL 塞进去。
state 必须绑定 session + 恒定时间比对,iris.Context 不自动帮你存
iris 的 ctx.Session().Set() 和 ctx.Session().Get() 是唯一靠谱的存储方式;别用 ctx.Values 或全局 map——它们不跨请求。
- 生成:crypto/rand.Read 取 32 字节,hex.EncodeToString 得到 64 字符字符串
- 存储:ctx.Session().Set("wechat_oauth_state", state),设过期时间(比如 10 分钟)
- 回调校验:先 ctx.Session().Get("wechat_oauth_state"),再用 subtle.ConstantTimeCompare 对比,**比完立刻 ctx.Session().Delete("wechat_oauth_state")**
- 错误现象:不删 state → 第二次登录失败;用 == 直接比 → 有计时攻击风险;存进 query 参数 → 被日志/代理泄露
callback handler 里 Exchange 失败,90% 是 context 或 body 被提前读空
iris 默认不缓存 r.Body,如果用了日志中间件、JWT 解析中间件,或者自己调了 ctx.PostValue,r.Body 就成空的了——conf.Exchange 发 POST 到微信 token 接口时 body 为空,返回 invalid_request。
- 必须传 ctx.Request().Context(),不是 context.Background();否则超时控制失效,微信响应慢时直接卡死
- 如果中间件已读 body,加一行恢复:ctx.Request().Body = io.NopCloser(bytes.NewBuffer(byt))(byt 是你之前读出的字节)
- 错误类型必须细判:err 是 *oauth2.RetrieveError 时,e.Response.StatusCode 和 e.Body 才是真实线索;打印 err.Error() 只能看到 “unable to retrieve token” 这种废话
拿到 access_token 后不能直接当用户信息用,必须调 /sns/userinfo
微信的 /sns/oauth2/access_token 接口只返回 access_token、expires_in、refresh_token、openid、scope,**没有昵称、头像、性别等任何用户资料**。
- 必须用 access_token + openid 再发 GET 请求到 https://api.weixin.qq.com/sns/userinfo
- 注意:这个接口返回的是 application/json;charset=utf-8,但响应体是 UTF-8 BOM 开头的 JSON,json.Unmarshal 会报错;得先 bytes.TrimPrefix(body, []byte("\xef\xbb\xbf"))
- openid 是微信内唯一标识,但不同公众号下同一个用户 openid 不同;如需跨公众号识别,得用 unionid(需用户关注过公众号且公众号开通了开放平台)
最易被忽略的点:微信的 redirect_uri 编码规则和 /sns/userinfo 的 BOM 处理,这两处不手动写死逻辑,其他都对也会静默失败。











