微信小程序登录核心是用js_code调用jscode2session获取openid,查库建用户并签发jwt;js_code需原样传递,url须正确拼接,session_key严禁外泄,jwt应含uid和合理exp,https全链路必须保障。

Gin 实现微信小程序后台接口,核心就三件事:用 js_code 换 openid、查/建用户、签发 JWT 返回。其余都是围绕这三点的容错、安全和部署细节。
怎么正确调用微信 jscode2session 接口
小程序前端调用 wx.login() 得到的临时登录凭证是 js_code(注意不是 code 或 jscode),后端必须原样传给微信接口。拼 URL 时别手写,用 fmt.Sprintf 构造:
url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appID, secret, jsCode)
常见报错 {"errcode":40029,"errmsg":"invalid code"},90% 是因为参数名写错或 URL 缺少 & 分隔符。另外,本地开发时不能用 localhost 或 127.0.0.1 直接请求微信接口——必须走公网 HTTPS 域名(哪怕只是 ngrok 转发)。
- 微信返回的
session_key绝对不能存进数据库、不能返回给前端、不能打日志 - 只在需要解密手机号等敏感数据时,用它做一次 AES 解密,解完立刻丢弃
- 如果返回
errcode != 0,直接返回错误,别尝试解析openid
用 openid 查用户并生成 JWT 的关键点
拿到 openid 后,查数据库时不要以它为主键做业务逻辑,而应查出对应用户的 ID(自增整型或 UUID)。JWT 签发要用 jwt-go v5+ 的新写法:
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"uid": user.ID,
"exp": time.Now().Add(24 * time.Hour).Unix(),
"iat": time.Now().Unix(),
})
signedToken, err := token.SignedString(yourSecretKey)
老教程里直接 new SigningMethodHS256 会 panic。你的密钥 yourSecretKey 必须是全局唯一的 []byte,从环境变量读,别硬编码字符串。
- JWT 中的
uid字段必须是数据库里的主键 ID,不是openid -
exp时间建议设为 24 小时以内,避免长期有效 token 泄露风险 - 别把
session_key或unionid塞进 JWT,它们不属于业务身份标识
微信消息签名验证(如公众号/小程序服务器配置)
微信服务器在接入时会发 GET 请求到你的接口,带 signature、timestamp、nonce 和 echostr 四个 query 参数。验证逻辑本质是 SHA1 签名比对:
把你在微信后台填的 token、收到的 timestamp、nonce 三个字符串放进切片,sort.Strings 排序后拼成一个字符串,再做 SHA1,最后跟 signature 对比。匹配就原样返回 echostr。
- 排序必须是字典序,不是时间戳大小序;漏掉排序或顺序错,签名永远不匹配
- 微信不会重复发这个请求,验证失败只能改代码重试,没重试机制
- 这个接口必须是 GET,且路径要和微信后台填写的「服务器地址」完全一致(包括末尾斜杠)
真正上线时最容易被忽略的是 HTTPS 全链路:小程序要求所有请求走 HTTPS,Nginx 要配好证书,Gin 服务本身不需要开 HTTPS(交给 Nginx 终止),但反向代理头(如 X-Forwarded-Proto)必须透传,否则 Gin 的 c.Request.URL.Scheme 会是 http,导致后续跳转或签名计算出错。











