• “微信小程序登录与用户信息获取详解“



    在这里插入图片描述

    引言

    在现代社交网络的时代,微信小程序作为一种快速、便捷的应用工具,受到了越来越多的关注和使用。其中,微信登录功能是小程序中最常见且重要的功能之一。本篇博客将深入介绍微信小程序登录的相关概念和实现方式,并重点探讨微信登录与用户信息获取的区别与联系。

    微信小程序微信登录介绍

    1. 微信登录的基本概念

    微信登录是指通过微信账号进行身份验证,使用户可以使用自己的微信账号登录到第三方应用或网站。微信登录减少了用户注册的繁琐过程,提供了更加便捷的登录体验。

    2. 微信小程序中的微信登录

    微信小程序中的微信登录功能允许用户使用微信账号登录小程序,并获取用户的基本信息。通过微信登录,小程序能够实现个性化的服务,提供更好的用户体验。

    微信小程序登录的wxLogin与getUserProfile的区别

    1. wx.login()

    1.1. 功能介绍
    wx.login() 是小程序提供的一个登录接口,用于获取用户的登录凭证 code。开发者可以通过该接口将 code 发送给服务器,以便获取用户的唯一标识 OpenID 和会话密钥 SessionKey。

    1.2. 使用场景
    wx.login() 适用于不需要获得用户详细信息的场景,比如只需要获取用户的 OpenID 进行身份验证等。

    2. wx.getUserProfile()

    2.1. 功能介绍
    wx.getUserProfile() 是小程序提供的一个获取用户信息的接口,可以获取用户的基本信息,包括昵称、头像、性别等。开发者可以通过该接口获取用户的个人信息,实现更加个性化的服务。

    2.2. 使用场景
    wx.getUserProfile() 适用于需要获取用户详细信息的场景,比如在用户授权后需要显示用户的个人资料页面等。

    3.两者区别

    区别在与wx,login()调用了方法即可获取信息,而wx.getUserProfile()需要在本来点击允许后才能获得信息。
    wx,login()不推荐使用

    微信小程序登录的理论概念

    1. 微信登录流程

    微信登录流程包括用户点击登录按钮、小程序调用 wx.login() 获取 code、小程序向服务器发送 code 并获取用户凭证等步骤。本节将详细介绍微信登录的整个流程及各个环节的作用。

    2. 用户授权与登录态维护

    用户授权是微信登录中的重要环节,通过用户的授权,小程序可以获取用户的基本信息。同时,小程序需要维护登录态,以确保用户在重新打开小程序时仍然处于登录状态。

    在这里插入图片描述

    • 说明

      • 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
      • 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 、 用户在微信开放平台帐号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台帐号) 和 会话密钥 session_key
      • 之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。
    • 注意事项

      1. 会话密钥 session_key 是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥
      2. 临时登录凭证 code 只能使用一次
    • appId 作用说明

      • appid 是微信账号的唯一标识,这个是固定不变的;
        如果了解微信公众号开发的就需要注意一下,小程序的appid 和 公众号的appid 是不一致的
    • session_key 功能说明
      微信客户端通过wx.getUserInfo()获取用户的信息
      后台有时候也需要获取微信客户端的用户信息,因此,就需要利用session_key这个秘钥来从微信平台中获取
      官方文档原文
      签名校验以及数据加解密涉及用户的会话密钥 session_key。 开发者应该事先通过 wx.login 登录流程获取会话密钥 session_key 并保存在服务器。为了数据不被篡改,开发者不应该把 session_key 传到小程序客户端等服务器外的环境。

    在这里插入图片描述

    微信小程序登录的代码演示

    1.getUserProfile登录

    • 1.点击登录–>点击微信直接登录–>点击允许
    
            // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
            // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
            wx.getUserProfile({
                desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
                success: (res) => {
                
                    //console.log(res);
                    debugger
                    user.checkLogin().catch(() => {
                        user.loginByWeixin(res.userInfo).then(res => {
                          app.globalData.hasLogin = true;
                          debugger
                          wx.navigateBack({
                            delta: 1
                          })
                        }).catch((err) => {
                          app.globalData.hasLogin = false;
                          if(err.errMsg=="request:fail timeout"){
                            util.showErrorToast('微信登录超时');
                          }else{
                            util.showErrorToast('微信登录失败');
                          }
                          this.setData({
                            lock:false
                          })
                        });
                      });
                },
                fail: (res) => {
                    app.globalData.hasLogin = false;
                    console.log(res);
                    util.showErrorToast('微信登录失败');
                }
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    user.checkLogin()方法检查之前有无登录情况

    /**
     * 判断用户是否登录
     */
    function checkLogin() {
      return new Promise(function(resolve, reject) {
        if (wx.getStorageSync('userInfo') && wx.getStorageSync('token')) {
          checkSession().then(() => {
            resolve(true);
          }).catch(() => {
            reject(false);
          });
        } else {
          reject(false);
        }
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如果没有登录过则会走异常方法然后调用loginByWeixin()方法携带code与用户信息请求后端

    /**
     * 调用微信登录
     */
    function loginByWeixin(userInfo) {
      return new Promise(function(resolve, reject) {
        return login().then((res) => {
          //登录远程服务器
          util.request(api.AuthLoginByWeixin, {
            code: res.code,
            userInfo: userInfo
          }, 'POST').then(res => {
            if (res.errno === 0) {
              //存储用户信息
              wx.setStorageSync('userInfo', res.data.userInfo);
              wx.setStorageSync('token', res.data.token);
              resolve(res);
            } else {
              reject(res);
            }
          }).catch((err) => {
            reject(err);
          });
        }).catch((err) => {
          reject(err);
        })
      });
    }
    /**
     * Promise封装wx.login
     */
    function login() {
      return new Promise(function(resolve, reject) {
        wx.login({
          success: function(res) {
            if (res.code) {
              resolve(res);
            } else {
              reject(res);
            }
          },
          fail: function(err) {
            reject(err);
          }
        });
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    后台拿到前台传过来的code和用户信息再拿到配好的密钥执行
    (WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(code);)访问微信服务器发送请求得到sessionKeyopenId
    然后再根据**WxUser user = userService.queryByOid(openId);**代码执行访问数据库查询有没有这个用户已登录的情况(查询有无记录)如果没有则会添加一个用户,如果有,那么修改访问时间
    然后再根据userId去生成一个Token令牌
    然后返回一个result

     /**
         * 微信登录
         *
         * @param wxLoginInfo
         *            请求内容,{ code: xxx, userInfo: xxx }
         * @param request
         *            请求对象
         * @return 登录结果
         */
        @PostMapping("login_by_weixin")
        public Object loginByWeixin(@RequestBody WxLoginInfo wxLoginInfo, HttpServletRequest request) {
    
            //客户端需携带code与userInfo信息
            String code = wxLoginInfo.getCode();
            UserInfo userInfo = wxLoginInfo.getUserInfo();
            if (code == null || userInfo == null) {
                return ResponseUtil.badArgument();
            }
            //调用微信sdk获取openId及sessionKey
            String sessionKey = null;
            String openId = null;
            try {
                long beginTime = System.currentTimeMillis();
                //
                WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(code);
    //            Thread.sleep(6000);
                long endTime = System.currentTimeMillis();
                log.info("响应时间:{}",(endTime-beginTime));
                sessionKey = result.getSessionKey();//session id
                openId = result.getOpenid();//用户唯一标识 OpenID
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            if (sessionKey == null || openId == null) {
                log.error("微信登录,调用官方接口失败:{}", code);
                return ResponseUtil.fail();
            }else{
                log.info("openId={},sessionKey={}",openId,sessionKey);
            }
            //根据openId查询wx_user表
            //如果不存在,初始化wx_user,并保存到数据库中
            //如果存在,更新最后登录时间
            WxUser user = userService.queryByOid(openId);
    
            if (user == null) {
                user = new WxUser();
                user.setUsername(openId);
                user.setPassword(openId);
                user.setWeixinOpenid(openId);
                user.setAvatar(userInfo.getAvatarUrl());
                user.setNickname(userInfo.getNickName());
                user.setGender(userInfo.getGender());
                user.setUserLevel((byte) 0);
                user.setStatus((byte) 0);
                user.setLastLoginTime(new Date());
                user.setLastLoginIp(IpUtil.client(request));
                user.setShareUserId(1);
    
                userService.add(user);
    
            } else {
                user.setLastLoginTime(new Date());
                user.setLastLoginIp(IpUtil.client(request));
                if (userService.updateById(user) == 0) {
                    log.error("修改失败:{}", user);
                    return ResponseUtil.updatedDataFailed();
                }
            }
            // token
            UserToken userToken = null;
            try {
                userToken = UserTokenManager.generateToken(user.getId());
            } catch (Exception e) {
                log.error("微信登录失败,生成token失败:{}", user.getId());
                e.printStackTrace();
                return ResponseUtil.fail();
            }
            userToken.setSessionKey(sessionKey);
            log.info("SessionKey={}",UserTokenManager.getSessionKey(user.getId()));
            Map<Object, Object> result = new HashMap<Object, Object>();
            result.put("token", userToken.getToken());
            result.put("tokenExpire", userToken.getExpireTime().toString());
            userInfo.setUserId(user.getId());
            if (!StringUtils.isEmpty(user.getMobile())) {// 手机号存在则设置
                userInfo.setPhone(user.getMobile());
            }
            try {
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                String registerDate = df.format(user.getAddTime() != null ? user.getAddTime() : new Date());
                userInfo.setRegisterDate(registerDate);
                userInfo.setStatus(user.getStatus());
                userInfo.setUserLevel(user.getUserLevel());// 用户层级
                userInfo.setUserLevelDesc(UserTypeEnum.getInstance(user.getUserLevel()).getDesc());// 用户层级描述
            } catch (Exception e) {
                log.error("微信登录:设置用户指定信息出错:"+e.getMessage());
                e.printStackTrace();
            }
            result.put("userInfo", userInfo);
    
    
            log.info("【请求结束】微信登录,响应结果:{}", JSONObject.toJSONString(result));
    
            return ResponseUtil.ok(result);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package cn.binarywang.wx.miniapp.api;
    
    import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
    import cn.binarywang.wx.miniapp.config.WxMaConfig;
    import me.chanjar.weixin.common.error.WxErrorException;
    import me.chanjar.weixin.common.util.http.RequestExecutor;
    import me.chanjar.weixin.common.util.http.RequestHttp;
    
    public interface WxMaService {
        String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
        String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";
    
        WxMaJscode2SessionResult jsCode2SessionInfo(String var1) throws WxErrorException;
    
        boolean checkSignature(String var1, String var2, String var3);
    
        String getAccessToken() throws WxErrorException;
    
        String getAccessToken(boolean var1) throws WxErrorException;
    
        String get(String var1, String var2) throws WxErrorException;
    
        String post(String var1, String var2) throws WxErrorException;
    
        <T, E> T execute(RequestExecutor<T, E> var1, String var2, E var3) throws WxErrorException;
    
        void setRetrySleepMillis(int var1);
    
        void setMaxRetryTimes(int var1);
    
        WxMaConfig getWxMaConfig();
    
        void setWxMaConfig(WxMaConfig var1);
    
        WxMaMsgService getMsgService();
    
        WxMaMediaService getMediaService();
    
        WxMaUserService getUserService();
    
        WxMaQrcodeService getQrcodeService();
    
        WxMaTemplateService getTemplateService();
    
        WxMaAnalysisService getAnalysisService();
    
        WxMaCodeService getCodeService();
    
        WxMaJsapiService getJsapiService();
    
        WxMaSettingService getSettingService();
    
        WxMaShareService getShareService();
    
        WxMaRunService getRunService();
    
        WxMaSecCheckService getSecCheckService();
    
        void initHttp();
    
        RequestHttp getRequestHttp();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    第二次登录

    package com.zking.ssm.wxcontroller;
    
    import java.math.BigDecimal;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Random;
    
    import com.zking.ssm.annotation.LoginUser;
    import com.zking.ssm.model.WxUser;
    import com.zking.ssm.service.UserTokenManager;
    import com.zking.ssm.service.WxUserService;
    import com.zking.ssm.util.ResponseUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;
    
    import com.alibaba.fastjson.JSONObject;
    
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    
    
    /**
     * 用户服务
     */
    @Slf4j
    @RestController
    @RequestMapping("/wx/user")
    @Validated
    public class WxUserController {
    	@Autowired
    	private WxUserService userService;
    
    	/**
    	 * 用户个人页面数据
    	 * 

    * @param userId * 用户ID * @return 用户个人页面数据 */ @GetMapping("index") public Object list(@LoginUser Integer userId, @RequestHeader("X-OA-token") String token) { log.info("【请求开始】用户个人页面数据,请求参数,userId:{}", userId); log.info("【请求开始】用户个人页面数据,请求参数,token:{}", token); if (userId == null) { log.error("用户个人页面数据查询失败:用户未登录!!!"); return ResponseUtil.unlogin(); } WxUser wxUser = userService.selectByPrimaryKey(userId); Map<Object, Object> data = new HashMap<Object, Object>(); data.put("metting_pubs", wxUser.getUserLevel()); data.put("metting_joins",wxUser.getUserLevel()); return ResponseUtil.ok(data); } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    微信表情包存储问题解决

    mysql的utf8编码的一个字符最多3个字节,但是一个emoji表情为4个字节,所以utf8不支持存储emoji表情。但是utf8的超集utf8mb4一个字符最多能有4字节,所以能支持emoji表情的存储。

    Linux系统中MySQL的配置文件为my.cnf。

    Winows中的配置文件为my.ini。

    utf8改为utf8mb4

    [mysql]
    # 设置mysql客户端默认字符集
    default-character-set=utf8mb4
    
    [mysqld]
    #设置3306端口
    port = 3306
    # 设置mysql的安装目录
    basedir=D:\\tools\\mysql-5.7.23-winx64
    # 设置mysql数据库的数据的存放目录
    datadir=D:\\tools\\mysql-5.7.23-winx64\\data
    # 允许最大连接数
    max_connections=200
    # 服务端使用的字符集默认为8比特编码的latin1字符集
    character-set-server=utf8mb4
    # 创建新表时将使用的默认存储引擎
    default-storage-engine=INNODB
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    总结

    本篇博客深入介绍了微信小程序登录的相关概念和实现方式,并重点探讨了微信登录与用户信息获取的区别与联系。通过对微信登录流程、用户授权与登录态维护的理论概念进行解析,结合代码演示和表情包存储问题的解决方案,希望能够帮助开发者更好地理解和应用微信小程序登录功能。

  • 相关阅读:
    菜谱APP源码和设计报告
    LeetCode——1678.设计 Goal 解析器
    Java 第1天:环境搭建
    spring jpa cassandra:查询日期timestamp 时间戳出现的一些问题
    centos7中多版本go安装
    Odoo 15开发手册第八章 业务逻辑 - 业务流程的支持
    知行电子口岸EDI端口介绍
    没有炫光的台灯有哪些?2023五款优秀护眼台灯
    Windows查看端口、结束任务进程(Nginx)
    EE5805-Java-summary
  • 原文地址:https://blog.csdn.net/2201_75869073/article/details/133963274