新版uniapp对接微信登录,前后端代码分享

由于微信在2.27.1以上的基础库调整了获取用户头像与名称的方法, 所以在这里记录一下

第一步, 使用uniapp的的uni.login方法, 获取用户的登录code

前端的代码

<button type="primary" class="btn-login" @click="getUserProfile">一键登录</button>


getUserProfile() {
	const _this = this
	uni.login({
		provider: 'weixin',
		success: async function(loginRes) {
                        //这里会拿到一个code, 5分钟之内有效
			_this.code = loginRes.code
                        
                        //这里用用户的code, 去送去后端
			const {
				data
			} = await uni.$http.post("wechat/session", {
				code: _this.code
			})
                         
                        //这里后端如果返回的是1, 说明用户没有注册昵称和头像, 跳转到注册页
			if (data.data.IsLogin === 1) {
				_this.openId == data.data.OpenID
				uni.navigateTo({
					url: `/subpkg/register/register?openId=${data.data.OpenID}`,

				})
                            //这里如果后端返回的是0, 说明用户注册过了, 把token, 头像, 名称存到本地, 跳转到用户的主页,保存用户的收藏到本地
			} else if (data.data.IsLogin === 0) {
				_this.saveLoginInfo({Token: data.data.OpenID, Name: data.data.Name, Avatar: data.data.Avatar})
				uni.switchTab({
					url: "/pages/my/my"
				})
				_this.saveLikes(data.data.Likes)
			}

		}
	});
}

后端的代码

func (wx *WX) Session(c *gin.Context) {
	codeBody := WechatSessionReqBody{}
	var err error
	if err = c.Bind(&codeBody); err != nil {
		app.NewResponse(c).ToResponse(code.InvalidParams)
		return
	}
        
        //这里凑请求, 拿用户的code, 小程序的appid,secret, 去换用户的openid和session_key
	url := fmt.Sprintf(code.WechatSessionUrl, global.WechatSetting.AppID, global.WechatSetting.AppSecret, codeBody.Code)
	resp := service.WechatSessionRespBody{}
	if err = service.HttpReq(http.MethodGet, url, nil, nil, 200, true, true, &resp); err != nil {
		app.NewResponse(c).ToErrorResponse(code.InvalidParams)
		return
	}
	user := models.User{}
         //找不到用户, 创建一个用户, 没有名字和昵称, 需要后续让用户填写以后再发过来
	if err = service.WhereQuery(&user, []string{code.DbWechatOpenID}, []string{resp.Openid}, nil, false); err != nil {
		if err == gorm.ErrRecordNotFound {
			user = models.User{}
			user.WechatSessionKey = resp.SessionKey
			user.WechatOpenid = resp.Openid
			if err = service.Create(&user); err != nil {
				global.Logger.Errorf("用户第一次登录, 创建用户失败:%v", err)
				app.NewResponse(c).ToErrorResponse(code.ServerError)
				return
			}
			app.NewResponse(c).ToResponse(LoginResp{
				IsLogin: 1,
				OpenID:  resp.Openid,
			})
			return
		} else {
			app.NewResponse(c).ToErrorResponse(code.ServerError)
			return
		}
	}

       //找到了用户, 但是用户的名称和头像为空, 需要后续让用户填写以后再发过来, 这里把请求回来的session_key更新下
	if user.Name == "" || user.AvatarUrl == "" {

		if err = service.Update(&models.User{}, code.DbWechatOpenID, resp.Openid, code.DbWechatSessionKey, resp.SessionKey); err != nil {
			global.Logger.Errorf("用户登录, 但头像和名称未填写, 保存用户的session失败:%v", err)
			app.NewResponse(c).ToErrorResponse(code.ServerError)
			return
		}
		app.NewResponse(c).ToResponse(LoginResp{
			IsLogin: 1,
			OpenID:  resp.Openid,
		})
		return
	}

       //到这里说明用户在数据库存在, 那么查出来用户的信息, 制作token,发给前端
	var token string
	if token, err = util.MakeToken(int(user.ID)); err != nil {
		global.Logger.Errorf("制作用户的token失败:%v", err)
		app.NewResponse(c).ToErrorResponse(code.UnauthorizedTokenGenerate)
		return
	}
        //这里把请求回来的session_key更新下
	if err = service.Update(&models.User{}, code.DbWechatOpenID, resp.Openid, code.DbWechatSessionKey, resp.SessionKey); err != nil {
		global.Logger.Errorf("用户登录,保存用户的session失败:%v", err)
		app.NewResponse(c).ToErrorResponse(code.ServerError)
		return
	}
	likes := make([]string, 0, len(user.Likes))
	key := code.RUserLike + strconv.Itoa(int(user.ID))
	if likes, err = service.SMEMBERS(key); err != nil {
		global.Logger.Errorf("从redis加载用户%s的喜欢列表失败:%v", user.Name, err)
	}

	app.NewResponse(c).ToResponse(LoginResp{
		IsLogin: 0,
		OpenID:  token,
		Name:    user.Name,
		Avatar:  user.AvatarUrl,
		Likes:   likes,
	})

}

第二步, 前端拿到openid, 跳转到用户注册页, 让用户填头像和昵称

前端的代码

<button open-type="chooseAvatar" class="avatar-wrapper" @chooseavatar="uploadAva">
input type="nickname" class="weui-input" @change="nick_nameChange" 
 :value="params.nickName" placeholder="请输入昵称" />


uploadAva(e) {
	let _this = this;
        //用户选择头像以后, 把头像和openid传到后端去, 后端把头像url传过来
	wx.getImageInfo({
		src: e.detail.avatarUrl,
		success(res) {
			uni.uploadFile({
				url: "https://xx/api/v1/wechat/upload",
				filePath: res.path,
				method: 'post',
				name: 'file',
				formData: {
                                        //带上openid, 因为每次文件名都会变, 我们需要用用户的openid来对应用户的头像
					openId: _this.params.openId,
				},
				success: async (r) => {
                                         //这里存下来用户的头像url
					_this.avatarUrl = JSON.parse(r.data).data;
					_this.params.avatar = JSON.parse(r.data).data

				}
			})
		}
	})
},

后端的代码

func (wx *WX) Upload(c *gin.Context) {
	form, err := c.MultipartForm()
	if err != nil {
		app.NewResponse(c).ToErrorResponse(code.InvalidParams)
		return
	}
        //拿到前端传过来的openid
	openIds, ok := form.Value["openId"]
	if !ok {
		app.NewResponse(c).ToErrorResponse(code.InvalidParams)
		return
	}
	if len(openIds) != 1 {
		app.NewResponse(c).ToErrorResponse(code.InvalidParams)
		return
	}
        
         //拿到用户传过来的头像文件
	file := form.File["file"]
	if len(file) != 1 {
		app.NewResponse(c).ToErrorResponse(code.InvalidParams)
		return
	}
	if file[0].Size > 1024*1024 {
		app.NewResponse(c).ToResponse(code.InvalidParams)
		return
	}

        //存下来, 把路径回给前端
	if err = c.SaveUploadedFile(file[0], filepath.Join(global.AvatarUploadPath, openIds[0]+".jpeg")); err != nil {
		app.NewResponse(c).ToResponse(code.InvalidParams)
		return
	}
	app.NewResponse(c).ToResponse("https://xxx/avatar/" + openIds[0] + ".jpeg")

}

第三步, 用户填完了信息, 点击了注册按钮

前端的代码就很简单, 不分享了, 就是直接调用后端的接口, 把用户的名称,头像url, openid带过来

func (wx *WX) Register(c *gin.Context) {
	var err error
	registerData := UserRegisterInfo{}
	if err = c.Bind(&registerData); err != nil {
		app.NewResponse(c).ToErrorResponse(code.InvalidParams)
		return
	}

	//用户的openid在数据库不存在, 直接报错
	user := models.User{}
	if err = service.WhereQuery(&user, []string{code.DbWechatOpenID}, []string{registerData.OpenID}, nil, false); err != nil {
		global.Logger.Error("用户不存在")
		app.NewResponse(c).ToErrorResponse(code.ServerError)
		return
	}
	uid := user.ID
	//更新用户的昵称
	if err = service.Update(&models.User{}, code.DbWechatOpenID, registerData.OpenID, "name", registerData.Name); err != nil {
		global.Logger.Errorf("保存用户的昵称到数据库失败:%v", err)
		app.NewResponse(c).ToErrorResponse(code.ServerError)
		return
	}
	//更新用户的头像
	if err = service.Update(&models.User{}, code.DbWechatOpenID, registerData.OpenID, "avatar_url", registerData.Avatar); err != nil {
		global.Logger.Errorf("保存用户的头像到数据库失败:%v", err)
		app.NewResponse(c).ToErrorResponse(code.ServerError)
		return
	}
	//制作token给前端
	var token string
	if token, err = util.MakeToken(int(uid)); err != nil {
		global.Logger.Errorf("制作用户的token失败:%v", err)
		app.NewResponse(c).ToErrorResponse(code.UnauthorizedTokenGenerate)
		return
	}
	app.NewResponse(c).ToResponse(LoginResp{
		IsLogin: 0,
		OpenID:  token,
		Name:    registerData.Name,
		Avatar:  registerData.Avatar,
	})

}

第四步, 注册成功,前端拿到token,用户信息等,存到本地


评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注