微信扫码登录
- 1. 简述:此文章目的主要是web网站进行微信扫码登录
- 2. 微信登录过程时序图
- 3. 全部微信登录组成元素
- 3.1. 微信扫码登录后端总共只需要两个接口,
- 3.2. 微信登录的各个对象:
- 3.3. 微信登录的主要参数:
- 4. 流程解释:
- 5. 容易产生的误解
1. 简述:此文章目的主要是web网站进行微信扫码登录
- 目的:希望用户通过微信扫码确认用户身份为其返回token
- 准备工作:网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。 在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者账号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。(没有审核过的没法使用完整版微信登录)
流程图:
2. 微信登录过程时序图
3. 全部微信登录组成元素
3.1. 微信扫码登录后端总共只需要两个接口,
- 接口一:即返回微信url的接口,参数有appId和redirectUrl,其中redirectUrl本身也是一个url,且这个url也携带了一些参数
代码一:
func Redirect(c *gin.Context) {
path := c.Query("Url")
state := Pcaptcha.RandString(5)
redirectURL := url.QueryEscape("http://" + path + "/api/v1/wechat/callback") //userinfo,
wechatLoginURL := fmt.Sprintf("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&state=%s&scope=snsapi_userinfo#wechat_redirect", "你的appid", redirectURL, state)
wechatLoginURL, _ = url.QueryUnescape(wechatLoginURL)
// 生成二维码
qrCode, err := qrcode.Encode(wechatLoginURL, qrcode.Medium, 256)
if err != nil {
// 错误处理
c.String(http.StatusInternalServerError, "Error generating QR code")
return
}
// 将二维码图片作为响应返回给用户
c.Header("Content-Type", "image/png")
c.Writer.Write(qrCode)
}
- 接口二:通过前端传来的code向微信服务器发送获取用户信息的请求,然后返回token
代码二:
func Callback(c *gin.Context) {
// 获取微信返回的授权码
code := c.Query("code")
// 向微信服务器发送请求,获取access_token和openid
tokenResp, err := http.Get(fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", "appid", "appsecret", code))
if err != nil {
fmt.Println(err)
resp := &ResponseData{
Data: nil,
Message: "error,获取token失败",
Code: CodeServerBusy,
}
c.JSON(http.StatusBadRequest, resp)
return
}
// 解析响应中的access_token和openid
var tokenData struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
OpenID string `json:"openid"`
Scope string `json:"scope"`
}
if err1 := json.NewDecoder(tokenResp.Body).Decode(&tokenData); err1 != nil {
resp := &ResponseData{
Data: nil,
Message: "error,获取token失败",
Code: CodeServerBusy,
}
c.JSON(http.StatusBadRequest, resp)
return
}
userInfoURL := fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s", tokenData.AccessToken, tokenData.OpenID)
userInfoResp, err := http.Get(userInfoURL)
if err != nil {
// 错误处理
zap.L().Error("获取失败")
return
}
defer userInfoResp.Body.Close()
//------------------------------------
var userData struct {
OpenID string `json:"openid"`
Nickname string `json:"nickname"`
}
if err1 := json.NewDecoder(userInfoResp.Body).Decode(&userData); err1 != nil {
// 错误处理
zap.L().Error("获取用户信息失败")
return
}
//用户的名字
var user1 model.User
nickname := userData.Nickname
if err2 := mysql.DB.Where("user_name=?", nickname).First(&user1).Error; err2 != nil {
if errors.Is(err2, gorm.ErrRecordNotFound) {
user1.UserName = nickname
user1.UserID, _ = snowflake.GetID()
user1.Identity = "普通用户"
} else {
zap.L().Error("验证登录信息过程中出错")
ResponseError(c, CodeServerBusy)
return
}
}
//添加jwt验证
atoken, rtoken, err3 := jwt.Token.GetToken(uint64(user1.UserID), user1.UserName, user1.Identity)
if err3 != nil {
zap.L().Error("生成JWT令牌失败")
return
}
c.Header("Authorization", atoken)
//发送成功响应
ResponseSuccess(c, &model.LoginData{
AccessToken: atoken,
RefreshToken: rtoken,
})
zap.L().Info("登录成功")
return
}
3.2. 微信登录的各个对象:
用户,前端(浏览器),前端服务器,后端服务器,微信服务器,手机
3.3. 微信登录的主要参数:
- appId:微信服务器确定是哪一个网站的凭证,向微信开发者平台申请获得
- redirectUrl:用户扫码完成后微信二维码页面根据这个url发送请求,如果这个redirectUrl是指向后端服务器的,后端根据code确认用户信息返回token,如果这个redirectUrl是指向前端服务器的,浏览器会向前端服务器发送请求,前端可以返回页面,在这个页面进行其他操作再向后端服务器发送携带code的获取token请求,后端再确认信息,返回token,
- code:用户扫码授权的凭证
4. 流程解释:
- 用户点击前端页面微信登录,前端发送获取微信url的请求,前端通过微信url向微信服务器发送获取微信二维码页面,并进行页面跳转,跳转到微信二维码页面供用户手机扫码,且微信二维码会一直轮询获取用户是否扫码,如果一定时间后用户没有扫码则二维码过期,停止轮询,页面可以点击刷新二维码,
- 用户扫码后并点击授权,微信二维码页面将轮询获得微信服务器中用户已授权的信息并获得code(code只能使用一次,且会过期)。微信二维码页面再根据code和接口一中的redirectUrl向后端服务器发送获取token的请求,后端根据code向微信服务器发送获取用户信息的http请求,获得的用户信息和数据库进行对比,如果一直则根据用户信息生成token并返回给前端,前端跳转页面实现微信登录
5. 容易产生的误解
- 前端向微信服务器发送获取微信二维码的请求之后跳转微信二维码页面,之后的扫码、轮询、是否授权、以及调用redirectUrl的链接都是微信页面在做的,不用我们去管他是如何实现的
- 微信二维码携带code发送的获取token请求,是在用户浏览器上发送的,我们返回token也是返回给了浏览器,浏览器会存储token的,但是如果要进行其他操作(业务方面的,如是否微信绑定,手机号绑定等)最好先跳转到自己的页面(redirect指向前端服务器,并获得前端的页面)。
最后有完整的微信登录项目代码包,可私信发送