• 带你深入了解微信小程序【授权登录】


           🏅我是默,一个在CSDN分享笔记的博主。📚📚

    🌟在这里,我要推荐给大家我的专栏《微信小程序 》。🎯🎯

    🚀无论你是编程小白,还是有一定基础的程序员,这个专栏都能满足你的需求。我会用最简单易懂的语言,带你走进代码的世界,让你从零开始,一步步成为编程大师。🚀🏆

    🌈让我们在代码的世界里畅游吧!🌈

    🎁如果感觉还不错的话请记得给我点赞哦!🎁🎁

    💖期待你的加入,一起学习,一起进步💖💖 

     一.了解微信登录的方法

    开放接口 /用户信息 /wx.getUserProfile

    wx.getUserProfile(Object object)

    用户头像昵称获取规则已调整,参考 小程序用户头像昵称获取规则调整公告

    基础库 2.10.4 开始支持,低版本需做兼容处理

    以 Promise 风格 调用:支持

    小程序插件:不支持

    微信 Windows 版:支持

    相关文档: 接口调用频率规范

    功能描述

    获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo。该接口用于替换 wx.getUserInfo,详见 用户信息接口调整说明

    参数

    Object object

    属性类型默认值必填说明
    langstringen显示用户信息的语言
    合法值说明
    en英文
    zh_CN简体中文
    zh_TW繁体中文
    descstring声明获取用户个人信息后的用途,不超过30个字符
    successfunction接口调用成功的回调函数
    failfunction接口调用失败的回调函数
    completefunction接口调用结束的回调函数(调用成功、失败都会执行)
    object.success 回调函数
    参数
    Object res
    属性类型说明最低版本
    userInfoUserInfo用户信息对象2.10.4
    rawDatastring不包括敏感信息的原始数据字符串,用于计算签名2.10.4
    signaturestring使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息,详见 用户数据的签名验证和加解密2.10.4
    encryptedDatastring包括敏感数据在内的完整用户信息的加密数据,详见 用户数据的签名验证和加解密2.10.4
    ivstring加密算法的初始向量,详见 用户数据的签名验证和加解密2.10.4
    cloudIDstring敏感数据对应的云 ID,开通云开发的小程序才会返回,可通过云调用直接获取开放数据,详细见云调用直接获取开放数据2.10.4

    示例代码

    在开发者工具中预览效果

    Bug & Tip

    1. tip:仅小程序中 wx.getUserInfo 接口进行调整,小游戏中不受影响;
    2. tip:开发者工具中仅 2.10.4 及以上版本可访问 wx.getUserProfile 接口,在真机上可参考示例代码进行判断,无需根据版本号或者 canIUse 进行条件。
    3. tipwx.getUserProfile 返回的加密数据中不包含 openId 和 unionId 字段。
    4. bug:开发者工具中 2.10.4~2.16.1 基础库版本通过 
    1. class="container">
    2. <view class="userinfo">
    3. <block wx:if="{{!hasUserInfo}}">
    4. <button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 button>
    5. <button wx:else open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 button>
    6. block>
    7. <block wx:else>
    8. <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover">image>
    9. <text class="userinfo-nickname">{{userInfo.nickName}}text>
    10. block>
    11. view>
    1. Page({
    2. data: {
    3. userInfo: {},
    4. hasUserInfo: false,
    5. canIUseGetUserProfile: false,
    6. },
    7. onLoad() {
    8. if (wx.getUserProfile) {
    9. this.setData({
    10. canIUseGetUserProfile: true
    11. })
    12. }
    13. },
    14. getUserProfile(e) {
    15. // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
    16. // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    17. wx.getUserProfile({
    18. desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
    19. success: (res) => {
    20. this.setData({
    21. userInfo: res.userInfo,
    22. hasUserInfo: true
    23. })
    24. }
    25. })
    26. },
    27. getUserInfo(e) {
    28. // 不推荐使用getUserInfo获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
    29. this.setData({
    30. userInfo: e.detail.userInfo,
    31. hasUserInfo: true
    32. })
    33. },
    34. })

    登录过程

    小程序登录

    小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系。

    • 说明

      • 调用 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导入后台的数据

    当然在导入的时候还要修改maven的配置即可


     

    1. /**
    2. *微信授权
    3. */
    4. @Slf4j
    5. @RestController
    6. @RequestMapping("/wx/auth")
    7. public class WxAuthController {
    8.     @Autowired
    9.     private WxMaService wxService;
    10.     @Autowired
    11.     private WxUserService userService;
    12.     /**
    13.      * 微信登录
    14.      *
    15.      * @param wxLoginInfo
    16.      *            请求内容,{ code: xxx, userInfo: xxx }
    17.      * @param request
    18.      *            请求对象
    19.      * @return 登录结果
    20.      */
    21.     @PostMapping("login_by_weixin")
    22.     public Object loginByWeixin(@RequestBody WxLoginInfo wxLoginInfo, HttpServletRequest request) {
    23.  
    24.         //客户端需携带code与userInfo信息
    25.         String code = wxLoginInfo.getCode();
    26.         UserInfo userInfo = wxLoginInfo.getUserInfo();
    27.         if (code == null || userInfo == null) {
    28.             return ResponseUtil.badArgument();
    29.         }
    30.         //调用微信sdk获取openId及sessionKey
    31.         String sessionKey = null;
    32.         String openId = null;
    33.         try {
    34.             long beginTime = System.currentTimeMillis();
    35.             //
    36.             WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(code);
    37. //            Thread.sleep(6000);
    38.             long endTime = System.currentTimeMillis();
    39.             log.info("响应时间:{}",(endTime-beginTime));
    40.             sessionKey = result.getSessionKey();//session id
    41.             openId = result.getOpenid();//用户唯一标识 OpenID
    42.         } catch (Exception e) {
    43.             e.printStackTrace();
    44.         }
    45.  
    46.         if (sessionKey == null || openId == null) {
    47.             log.error("微信登录,调用官方接口失败:{}", code);
    48.             return ResponseUtil.fail();
    49.         }else{
    50.             log.info("openId={},sessionKey={}",openId,sessionKey);
    51.         }
    52.         //根据openId查询wx_user表
    53.         //如果不存在,初始化wx_user,并保存到数据库中
    54.         //如果存在,更新最后登录时间
    55.         WxUser user = userService.queryByOid(openId);
    56.  
    57.         if (user == null) {
    58.             user = new WxUser();
    59.             user.setUsername(openId);
    60.             user.setPassword(openId);
    61.             user.setWeixinOpenid(openId);
    62.             user.setAvatar(userInfo.getAvatarUrl());
    63.             user.setNickname(userInfo.getNickName());
    64.             user.setGender(userInfo.getGender());
    65.             user.setUserLevel((byte) 0);
    66.             user.setStatus((byte) 0);
    67.             user.setLastLoginTime(new Date());
    68.             user.setLastLoginIp(IpUtil.client(request));
    69.             user.setShareUserId(1);
    70.  
    71.             userService.add(user);
    72.  
    73.         } else {
    74.             user.setLastLoginTime(new Date());
    75.             user.setLastLoginIp(IpUtil.client(request));
    76.             if (userService.updateById(user) == 0) {
    77.                 log.error("修改失败:{}", user);
    78.                 return ResponseUtil.updatedDataFailed();
    79.             }
    80.         }
    81.         // token
    82.         UserToken userToken = null;
    83.         try {
    84.             userToken = UserTokenManager.generateToken(user.getId());
    85.         } catch (Exception e) {
    86.             log.error("微信登录失败,生成token失败:{}", user.getId());
    87.             e.printStackTrace();
    88.             return ResponseUtil.fail();
    89.         }
    90.         userToken.setSessionKey(sessionKey);
    91.         log.info("SessionKey={}",UserTokenManager.getSessionKey(user.getId()));
    92.         Map<Object, Object> result = new HashMap<Object, Object>();
    93.         result.put("token", userToken.getToken());
    94.         result.put("tokenExpire", userToken.getExpireTime().toString());
    95.         userInfo.setUserId(user.getId());
    96.         if (!StringUtils.isEmpty(user.getMobile())) {// 手机号存在则设置
    97.             userInfo.setPhone(user.getMobile());
    98.         }
    99.         try {
    100.             DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    101.             String registerDate = df.format(user.getAddTime() != null ? user.getAddTime() : new Date());
    102.             userInfo.setRegisterDate(registerDate);
    103.             userInfo.setStatus(user.getStatus());
    104.             userInfo.setUserLevel(user.getUserLevel());// 用户层级
    105.             userInfo.setUserLevelDesc(UserTypeEnum.getInstance(user.getUserLevel()).getDesc());// 用户层级描述
    106.         } catch (Exception e) {
    107.             log.error("微信登录:设置用户指定信息出错:"+e.getMessage());
    108.             e.printStackTrace();
    109.         }
    110.         result.put("userInfo", userInfo);
    111.  
    112.  
    113.         log.info("【请求结束】微信登录,响应结果:{}", JSONObject.toJSONString(result));
    114.  
    115.         return ResponseUtil.ok(result);
    116.     }

     

     2.导入前端数据

    导入即可但是要修改成自己的小程序id

    1.       3.2 前端代码:
    2.         login.wxml代码:
    3. "container">
    4.   "login-box">
    5.    
    6.    
    7.    
    8.  
    9.        login.js:
    10. // pages/auth/login/login.js
    11. var util = require('../../../utils/util.js');
    12. var user = require('../../../utils/user.js');
    13. const app = getApp();
    14. Page({
    15.  
    16.     /**
    17.      * 页面的初始数据
    18.      */
    19.     data: {
    20.         canIUseGetUserProfile: false, // 用于向前兼容
    21.         lock:false
    22.     },
    23.     onLoad: function(options) {
    24.         // 页面初始化 options为页面跳转所带来的参数
    25.         // 页面渲染完成
    26.         if (wx.getUserProfile) {
    27.           this.setData({
    28.             canIUseGetUserProfile: true
    29.           })
    30.         }
    31.         //console.log('login.onLoad.canIUseGetUserProfile='+this.data.canIUseGetUserProfile)
    32.     },
    33.  
    34.     /**
    35.      * 生命周期函数--监听页面初次渲染完成
    36.      */
    37.     onReady() {
    38.  
    39.     },
    40.  
    41.     /**
    42.      * 生命周期函数--监听页面显示
    43.      */
    44.     onShow() {
    45.  
    46.     },
    47.     getUserProfile(e) {
    48.         // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
    49.         // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    50.         wx.getUserProfile({
    51.             desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
    52.             success: (res) => {
    53.                 //console.log(res);
    54.                 debugger
    55.                 user.checkLogin().catch(() => {
    56.                     user.loginByWeixin(res.userInfo).then(res => {
    57.                       app.globalData.hasLogin = true;
    58.                       debugger
    59.                       wx.navigateBack({
    60.                         delta: 1
    61.                       })
    62.                     }).catch((err) => {
    63.                       app.globalData.hasLogin = false;
    64.                       if(err.errMsg=="request:fail timeout"){
    65.                         util.showErrorToast('微信登录超时');
    66.                       }else{
    67.                         util.showErrorToast('微信登录失败');
    68.                       }
    69.                       this.setData({
    70.                         lock:false
    71.                       })
    72.                     });
    73.                   });
    74.             },
    75.             fail: (res) => {
    76.                 app.globalData.hasLogin = false;
    77.                 console.log(res);
    78.                 util.showErrorToast('微信登录失败');
    79.             }
    80.         });
    81.     },
    82.     wxLogin: function(e) {
    83.         if (e.detail.userInfo == undefined) {
    84.           app.globalData.hasLogin = false;
    85.           util.showErrorToast('微信登录失败');
    86.           return;
    87.         }
    88.         user.checkLogin().catch(() => {
    89.             user.loginByWeixin(e.detail.userInfo).then(res => {
    90.               app.globalData.hasLogin = true;
    91.               wx.navigateBack({
    92.                 delta: 1
    93.               })
    94.             }).catch((err) => {
    95.               app.globalData.hasLogin = false;
    96.               if(err.errMsg=="request:fail timeout"){
    97.                 util.showErrorToast('微信登录超时');
    98.               }else{
    99.                 util.showErrorToast('微信登录失败');
    100.               }
    101.             });
    102.       
    103.           });
    104.     },
    105.     accountLogin() {
    106.         console.log('开发中....')
    107.     }
    108.  
    109. })
    110. config/api.js代码,连接接口
    111. // 以下是业务服务器API地址
    112.  // 本机开发API地址
    113. var WxApiRoot = 'http://localhost:8080/oapro/wx/';
    114. // 测试环境部署api地址
    115. // var WxApiRoot = 'http://192.168.191.1:8080/oapro/wx/';
    116. // 线上平台api地址
    117. //var WxApiRoot = 'https://www.oa-mini.com/demo/wx/';
    118.  
    119. module.exports = {
    120.   IndexUrl: WxApiRoot + 'home/index', //首页数据接口
    121.   SwiperImgs: WxApiRoot+'swiperImgs',
    122.   MettingInfos: WxApiRoot+'meeting/list',
    123.   AuthLoginByWeixin: WxApiRoot + 'auth/login_by_weixin', //微信登录
    124.   UserIndex: WxApiRoot + 'user/index', //个人页面用户相关信息
    125.   AuthLogout: WxApiRoot + 'auth/logout', //账号登出
    126.   AuthBindPhone: WxApiRoot + 'auth/bindPhone' //绑定微信手机号
    127. };
    128. 微信登录工具类utils/util.js:
    129. function formatTime(date) {
    130.   var year = date.getFullYear()
    131.   var month = date.getMonth() + 1
    132.   var day = date.getDate()
    133.  
    134.   var hour = date.getHours()
    135.   var minute = date.getMinutes()
    136.   var second = date.getSeconds()
    137.  
    138.   return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':')
    139. }
    140.  
    141. function formatNumber(n) {
    142.   n = n.toString()
    143.   return n[1] ? n : '0' + n
    144. }
    145.  
    146.  
    147. /**
    148.  * 封封微信的的request
    149.  */
    150. function request(url, data = {}, method = "GET") {
    151.   return new Promise(function (resolve, reject) {
    152.     wx.request({
    153.       url: url,
    154.       data: data,
    155.       method: method,
    156.       timeout:3000,
    157.       header: {
    158.         'Content-Type': 'application/json',
    159.         'X-OA-Token': wx.getStorageSync('token')
    160.       },
    161.       success: function (res) {
    162.         if (res.statusCode == 200) {
    163.           if (res.data.errno == 501) {
    164.             // 清除登录相关内容
    165.             try {
    166.               wx.removeStorageSync('userInfo');
    167.               wx.removeStorageSync('token');
    168.             } catch (e) {
    169.               // Do something when catch error
    170.             }
    171.             // 切换到登录页面
    172.             wx.navigateTo({
    173.               url: '/pages/auth/login/login'
    174.             });
    175.           } else {
    176.             resolve(res.data);
    177.           }
    178.         } else {
    179.           reject(res.errMsg);
    180.         }
    181.  
    182.       },
    183.       fail: function (err) {
    184.         reject(err)
    185.       }
    186.     })
    187.   });
    188. }
    189.  
    190. function redirect(url) {
    191.   //判断页面是否需要登录
    192.   if (false) {
    193.     wx.redirectTo({
    194.       url: '/pages/auth/login/login'
    195.     });
    196.     return false;
    197.   } else {
    198.     wx.redirectTo({
    199.       url: url
    200.     });
    201.   }
    202. }
    203.  
    204. function showErrorToast(msg) {
    205.   wx.showToast({
    206.     title: msg,
    207.     image: '/static/images/icon_error.png'
    208.   })
    209. }
    210.  
    211. function jhxLoadShow(message) {
    212.   if (wx.showLoading) { // 基础库 1.1.0 微信6.5.6版本开始支持,低版本需做兼容处理
    213.     wx.showLoading({
    214.       title: message,
    215.       mask: true
    216.     });
    217.   } else { // 低版本采用Toast兼容处理并将时间设为20秒以免自动消失
    218.     wx.showToast({
    219.       title: message,
    220.       icon: 'loading',
    221.       mask: true,
    222.       duration: 20000
    223.     });
    224.   }
    225. }
    226.  
    227. function jhxLoadHide() {
    228.   if (wx.hideLoading) { // 基础库 1.1.0 微信6.5.6版本开始支持,低版本需做兼容处理
    229.     wx.hideLoading();
    230.   } else {
    231.     wx.hideToast();
    232.   }
    233. }
    234.  
    235. module.exports = {
    236.   formatTime,
    237.   request,
    238.   redirect,
    239.   showErrorToast,
    240.   jhxLoadShow,
    241.   jhxLoadHide
    242. }
    243. 判断用户是否登录 user.js:
    244. /**
    245.  * 用户相关服务
    246.  */
    247. const util = require('../utils/util.js');
    248. const api = require('../config/api.js');
    249.  
    250. /**
    251.  * Promise封装wx.checkSession
    252.  */
    253. function checkSession() {
    254.   return new Promise(function(resolve, reject) {
    255.     wx.checkSession({
    256.       success: function() {
    257.         resolve(true);
    258.       },
    259.       fail: function() {
    260.         reject(false);
    261.       }
    262.     })
    263.   });
    264. }
    265. /**
    266.  * Promise封装wx.login
    267.  */
    268. function login() {
    269.   return new Promise(function(resolve, reject) {
    270.     wx.login({
    271.       success: function(res) {
    272.         if (res.code) {
    273.           resolve(res);
    274.         } else {
    275.           reject(res);
    276.         }
    277.       },
    278.       fail: function(err) {
    279.         reject(err);
    280.       }
    281.     });
    282.   });
    283. }
    284. /**
    285.  * 调用微信登录
    286.  */
    287. function loginByWeixin(userInfo) {
    288.   return new Promise(function(resolve, reject) {
    289.     return login().then((res) => {
    290.       //登录远程服务器
    291.       util.request(api.AuthLoginByWeixin, {
    292.         code: res.code,
    293.         userInfo: userInfo
    294.       }, 'POST').then(res => {
    295.         if (res.errno === 0) {
    296.           //存储用户信息
    297.           wx.setStorageSync('userInfo', res.data.userInfo);
    298.           wx.setStorageSync('token', res.data.token);
    299.           resolve(res);
    300.         } else {
    301.           reject(res);
    302.         }
    303.       }).catch((err) => {
    304.         reject(err);
    305.       });
    306.     }).catch((err) => {
    307.       reject(err);
    308.     })
    309.   });
    310. }
    311.  
    312. /**
    313.  * 判断用户是否登录
    314.  */
    315. function checkLogin() {
    316.   return new Promise(function(resolve, reject) {
    317.     if (wx.getStorageSync('userInfo') && wx.getStorageSync('token')) {
    318.       checkSession().then(() => {
    319.         resolve(true);
    320.       }).catch(() => {
    321.         reject(false);
    322.       });
    323.     } else {
    324.       reject(false);
    325.     }
    326.   });
    327. }
    328.  
    329. module.exports = {
    330.   loginByWeixin,
    331.   checkLogin,
    332. };

    3.效果展示

    4.表情问题

  • 相关阅读:
    链路ID通过MDC实现线程间传递
    Android中常用Dialog的使用
    老司机必备的手机浏览器,比UC浏览器还好用
    交叉编译工具的安装和配置过程介绍
    进阶JAVA篇- BigDecimal 类的常用API(四)
    【Android进阶】11、操作数据库:Room 库、repository 模式和 LiveData
    Springboot + Mybatis-Plus开启二级缓存
    基于SpringBoot+Vue+uniapp的企业人事管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
    【宋红康 MySQL数据库 】【高级篇】【11】索引的设计原则
    数据结构与算法(Java版) | 几个经典的算法面试题(上)
  • 原文地址:https://blog.csdn.net/lz17267861157/article/details/133963553