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