由于微信在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(®isterData); 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, }) }
发表回复