当前位置:   article > 正文

微信小程序之后台交互-个人中心_博客类微信小程序+后台

博客类微信小程序+后台

目录

一.小程序登录微信登录接口演示

导入项目

登录信息  

二.小程序授权登录理论与登录代码演示

图解

​编辑

后端代码

前端代码 

前端代码如下所示

代码案例演示

个人中心

后端代码如下所示

 测试结果如下


一.小程序登录微信登录接口演示

导入项目

选择此项目导入 

 

登录信息  

如使用false的话它不会弹出确认登录框,所有不介意使用这个

 

测试结果 

如使用true则会跳出确认登录 

 

测试结果

 

二.小程序授权登录理论与登录代码演示


微信小程序的授权登录过程通常包括以下几个步骤:

小程序初始化: 在小程序初始化的时候,可以调用 wx.login 接口获取临时登录凭证 code。这个 code 的有效期很短,通常只有几分钟,所以需要在获取到 code 后尽快使用。

将 code 发送到开发者服务器: 小程序前端通过网络请求将获取到的 code 发送到开发者服务器。

开发者服务器获取 session_key 和 openid: 开发者服务器收到 code 后,可以将其发送到微信服务器的登录凭证校验接口,换取 session_key 和 openid。session_key 是会话密钥,用于加密数据传输,openid 是用户在当前小程序的唯一标识。

校验登录状态: 开发者服务器使用获取到的 session_key 和 openid 创建一个用户登录态,同时生成一个自定义的登录态标识,例如 token,并将这个标识返回给小程序前端。

小程序前端存储登录态: 小程序前端收到开发者服务器返回的登录态标识后,可以将它存储在本地,一般存储在缓存中。

后续请求携带登录态: 小程序前端在后续的网络请求中,可以在请求的 header 中携带这个登录态标识,以表明当前请求是一个已登录用户发起的。

图解

后端代码

 导入后端登录代码

前端代码 

导入前端登录代码 

 

前端代码如下所示

代码案例演示

调用接口地址

api.js

  1. // 以下是业务服务器API地址
  2. // 本机开发API地址
  3. var WxApiRoot = 'http://localhost:8080/oapro/wx/';
  4. // 测试环境部署api地址
  5. // var WxApiRoot = 'http://192.168.191.1:8080/oapro/wx/';
  6. // 线上平台api地址
  7. //var WxApiRoot = 'https://www.oa-mini.com/demo/wx/';
  8. module.exports = {
  9. IndexUrl: WxApiRoot + 'home/index', //首页数据接口
  10. SwiperImgs: WxApiRoot+'swiperImgs',
  11. MettingInfos: WxApiRoot+'meeting/list',
  12. AuthLoginByWeixin: WxApiRoot + 'auth/login_by_weixin', //微信登录
  13. UserIndex: WxApiRoot + 'user/index', //个人页面用户相关信息
  14. AuthLogout: WxApiRoot + 'auth/logout', //账号登出
  15. AuthBindPhone: WxApiRoot + 'auth/bindPhone' //绑定微信手机号
  16. };
个人中心

编写index.wxml

  1. <view class="page-container">
  2. <view class="user-info-container">
  3. <view class="user-info" bindtap="goLogin">
  4. <image class="user-img" mode="scaleToFill" src="{{userInfo.avatarUrl}}" />
  5. <text class="user-info-name">{{userInfo.nickName}}</text>
  6. </view>
  7. <image class="user-update" src="/static/tabBar/component.png" bindtap='goPages' data-url='/pages/ucenter/user/user'/>
  8. </view>
  9. <view class="boundary" />
  10. <view class="cells-container">
  11. <view class="cell-wrap">
  12. <image class="cell-icon" src="/static/tabBar/sdk.png" />
  13. <text class="cell-text">我主持的会议</text>
  14. <view class="cell-right">
  15. <view class="cell-list-num">{{metting_pubs}}</view>
  16. <view class="cell-arrow"></view>
  17. </view>
  18. </view>
  19. <view class="cell-wrap">
  20. <image class="cell-icon" src="/static/tabBar/sdk.png" />
  21. <text class="cell-text">我参与的会议</text>
  22. <view class="cell-right">
  23. <view class="cell-list-num">{{metting_joins}}</view>
  24. <view class="cell-arrow"></view>
  25. </view>
  26. </view>
  27. </view>
  28. <view class="boundary" />
  29. <view class="cells-container">
  30. <view class="cell-wrap">
  31. <image class="cell-icon" src="/static/tabBar/sdk.png" />
  32. <text class="cell-text">我发布的投票</text>
  33. <view class="cell-right">
  34. <view class="cell-list-num">1</view>
  35. <view class="cell-arrow"></view>
  36. </view>
  37. </view>
  38. <view class="cell-wrap">
  39. <image class="cell-icon" src="/static/tabBar/sdk.png" />
  40. <text class="cell-text">我参与的投票</text>
  41. <view class="cell-right">
  42. <view class="cell-list-num">10</view>
  43. <view class="cell-arrow"></view>
  44. </view>
  45. </view>
  46. </view>
  47. <view class="boundary" />
  48. <view class="cells-container">
  49. <view class="cell-wrap">
  50. <image class="cell-icon" src="/static/tabBar/template.png" />
  51. <text class="cell-text">消息</text>
  52. <view class="cell-right">
  53. <view class="cell-list-num"></view>
  54. <view class="cell-arrow"></view>
  55. </view>
  56. </view>
  57. <view class="cell-wrap">
  58. <image class="cell-icon" src="/static/tabBar/component.png" />
  59. <text class="cell-text">设置</text>
  60. <view class="cell-right">
  61. <view class="cell-list-num"></view>
  62. <view class="cell-arrow"></view>
  63. </view>
  64. </view>
  65. </view>
  66. </view>

 编写index.js

  1. // pages/ucenter/index/index.js
  2. var util = require('../../../utils/util.js');
  3. var api = require('../../../config/api.js');
  4. const app = getApp();
  5. Page({
  6. /**
  7. * 页面的初始数据
  8. */
  9. data: {
  10. userInfo: {
  11. nickName: '点击登录',
  12. avatarUrl: '/static/images/avatar.png'
  13. },
  14. hasLogin: false,
  15. metting_pubs: '',
  16. metting_joins: ''
  17. },
  18. /**
  19. * 生命周期函数--监听页面加载
  20. */
  21. onLoad(options) {
  22. },
  23. /**
  24. * 生命周期函数--监听页面显示
  25. */
  26. onShow() {
  27. this.getUserInfo();
  28. },
  29. getUserInfo() {
  30. // console.log('ucenter.index.app.globalData.hasLogin='+app.globalData.hasLogin)
  31. //获取用户的登录信息
  32. if (app.globalData.hasLogin) {
  33. let userInfo = wx.getStorageSync('userInfo');
  34. this.setData({
  35. userInfo: userInfo,
  36. hasLogin: true
  37. });
  38. //查询个人统计信息
  39. util.request(api.UserIndex).then(res => {
  40. if (res.errno === 0) {
  41. this.setData({
  42. metting_pubs: res.data.metting_pubs,
  43. metting_joins: res.data.metting_joins
  44. });
  45. }
  46. });
  47. }
  48. },
  49. goLogin() {
  50. if (!this.data.hasLogin) {
  51. wx.navigateTo({
  52. url: "/pages/auth/login/login"
  53. });
  54. }
  55. },
  56. /**
  57. * 页面跳转
  58. */
  59. goPages: function (e) {
  60. if (this.data.hasLogin) {
  61. wx.navigateTo({
  62. url: e.currentTarget.dataset.url
  63. });
  64. } else {
  65. wx.navigateTo({
  66. url: "/pages/auth/login/login"
  67. });
  68. };
  69. }
  70. })

 

创建一个用户登入后的设置页面为 : user。

user.js

  1. var util = require('../../../utils/util.js');
  2. var api = require('../../../config/api.js');
  3. var user = require('../../../utils/user.js');
  4. var app = getApp();
  5. Page({
  6. /**
  7. * 页面的初始数据
  8. */
  9. data: {
  10. userInfo: {},
  11. hasLogin: false,
  12. userSharedUrl: ''
  13. },
  14. /**
  15. * 生命周期函数--监听页面加载
  16. */
  17. onLoad: function (options) {
  18. },
  19. onShow: function () {
  20. let that = this;
  21. //获取用户的登录信息
  22. let userInfo = wx.getStorageSync('userInfo');
  23. this.setData({
  24. userInfo: userInfo,
  25. hasLogin: true
  26. });
  27. },
  28. getPhoneNumber: function (e) {
  29. let that = this;
  30. if (e.detail.errMsg !== "getPhoneNumber:ok") {
  31. // 拒绝授权
  32. return;
  33. }
  34. if (!this.data.hasLogin) {
  35. wx.showToast({
  36. title: '绑定失败:请先登录',
  37. icon: 'none',
  38. duration: 2000
  39. });
  40. return;
  41. }
  42. util.request(api.AuthBindPhone, {
  43. iv: e.detail.iv,
  44. encryptedData: e.detail.encryptedData
  45. }, 'POST').then(function (res) {
  46. if (res.errno === 0) {
  47. let userInfo = wx.getStorageSync('userInfo');
  48. userInfo.phone = res.data.phone;//设置手机号码
  49. wx.setStorageSync('userInfo', userInfo);
  50. that.setData({
  51. userInfo: userInfo,
  52. hasLogin: true
  53. });
  54. wx.showToast({
  55. title: '绑定手机号码成功',
  56. icon: 'success',
  57. duration: 2000
  58. });
  59. }
  60. });
  61. },
  62. exitLogin: function () {
  63. wx.showModal({
  64. title: '',
  65. confirmColor: '#b4282d',
  66. content: '退出登录?',
  67. success: function (res) {
  68. if (!res.confirm) {
  69. return;
  70. }
  71. util.request(api.AuthLogout, {}, 'POST');
  72. app.globalData.hasLogin = false;
  73. wx.removeStorageSync('token');
  74. wx.removeStorageSync('userInfo');
  75. wx.reLaunch({
  76. url: '/pages/index/index'
  77. });
  78. }
  79. })
  80. }
  81. })

编写user.wxml 

  1. <!--pages/ucenter/user/user.wxml-->
  2. <form bindsubmit="formSubmit">
  3. <view class='personal-data'>
  4. <view class='list'>
  5. <view class='item acea-row row-between-wrapper'>
  6. <view>头像</view>
  7. <view class='pictrue'>
  8. <image src='{{userInfo.avatarUrl}}'></image>
  9. </view>
  10. </view>
  11. <view class='item acea-row row-between-wrapper'>
  12. <view>名字</view>
  13. <view class='input'><input type='text' disabled='true' name='nickname' value='{{userInfo.nickName}}'></input></view>
  14. </view>
  15. <view class='item acea-row row-between-wrapper'>
  16. <view>手机号码</view>
  17. <button name='phone' class='phone' value='{{userInfo.phone}}' wx:if="{{!userInfo.phone}}" bindgetphonenumber="getPhoneNumber" hover-class='none' open-type='getPhoneNumber'>
  18. 点击获取
  19. </button>
  20. <view class='input acea-row row-between-wrapper' wx:else>
  21. <input type='text' disabled='true' name='phone' value='{{userInfo.phone}}' class='id'></input>
  22. <text class='iconfont icon-suozi'></text>
  23. </view>
  24. </view>
  25. <view class='item acea-row row-between-wrapper'>
  26. <view>ID号</view>
  27. <view class='input acea-row row-between-wrapper'>
  28. <input type='text' value='1000{{userInfo.userId}}' disabled='true' class='id'></input>
  29. <text class='iconfont icon-suozi'></text>
  30. </view>
  31. </view>
  32. </view>
  33. <button class='modifyBnt' bindtap="exitLogin">退 出</button>
  34. </view>
  35. </form>

编写user.wxss

  1. @import '/static/font/iconfont.wxss';
  2. .personal-data .list {
  3. margin-top: 15rpx;
  4. background-color: #fff;
  5. }
  6. .personal-data .list .item {
  7. padding: 30rpx 30rpx 30rpx 0;
  8. border-bottom: 1rpx solid #f2f2f2;
  9. margin-left: 30rpx;
  10. font-size: 32rpx;
  11. color: #282828;
  12. }
  13. .personal-data .list .item .phone {
  14. background-color: #85c43f;
  15. width: 160rpx;
  16. height: 56rpx;
  17. font-size: 24rpx;
  18. color: #fff;
  19. line-height: 56rpx;
  20. border-radius: 32rpx
  21. }
  22. .personal-data .list .item .pictrue {
  23. width: 88rpx;
  24. height: 88rpx;
  25. }
  26. .personal-data .list .item .pictrue image {
  27. width: 100%;
  28. height: 100%;
  29. border-radius: 50%;
  30. }
  31. .personal-data .list .item .input {
  32. width: 415rpx;
  33. text-align: right;
  34. color: #868686;
  35. }
  36. .personal-data .list .item .input .id {
  37. width: 365rpx;
  38. }
  39. .personal-data .list .item .input .iconfont {
  40. font-size: 35rpx;
  41. }
  42. .personal-data .modifyBnt {
  43. /* background-color: #85c43f; */
  44. /* background: linear-gradient(to left right, #85c43f, #fefefd); */
  45. background: radial-gradient(circle at 50%,#85c43f,#CDDC39);
  46. font-size: 32rpx;
  47. color: #fff;
  48. width: 690rpx;
  49. height: 90rpx;
  50. border-radius: 50rpx;
  51. display: flex;
  52. justify-content: center;
  53. align-items: center;
  54. line-height: 90rpx;
  55. margin: 76rpx auto 0 auto;
  56. }
  57. .acea-row{display:flex;flex-wrap:wrap;}
  58. .acea-row.row-top{align-items:flex-start;}
  59. .acea-row.row-middle{align-items:center;}
  60. .acea-row.row-bottom{align-items:flex-end;}
  61. .acea-row.row-left{justify-content:flex-start;}
  62. .acea-row.row-center{justify-content:center;}
  63. .acea-row.row-right{justify-content:flex-end;}
  64. .acea-row.row-between{justify-content:space-between;}
  65. .acea-row.row-around{justify-content:space-around;}
  66. .acea-row.row-column{flex-direction:column;}
  67. .acea-row.row-column-between{flex-direction:column;justify-content:space-between;}
  68. .acea-row.row-column-around{flex-direction:column;justify-content:space-around;}
  69. .acea-row.row-center-wrapper{align-items:center;justify-content:center;}
  70. .acea-row.row-between-wrapper{align-items:center;justify-content:space-between;}
  71. view, image, text, navigator {
  72. box-sizing: border-box;
  73. padding: 0;
  74. margin: 0;
  75. }

后端代码如下所示

在后台编写的控制器,来进行出来前端的请求及数据处理并且反馈带前端

WxAuthController : 

  1. package com.zking.ssm.wxcontroller;
  2. /**
  3. * @Autho donkee
  4. * @Since 2022/6/27
  5. */
  6. import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
  7. import com.alibaba.fastjson.JSONObject;
  8. import com.zking.ssm.annotation.LoginUser;
  9. import com.zking.ssm.model.UserInfo;
  10. import com.zking.ssm.model.WxLoginInfo;
  11. import com.zking.ssm.model.WxUser;
  12. import com.zking.ssm.service.UserToken;
  13. import com.zking.ssm.service.UserTokenManager;
  14. import com.zking.ssm.service.WxUserService;
  15. import com.zking.ssm.util.JacksonUtil;
  16. import com.zking.ssm.util.ResponseUtil;
  17. import com.zking.ssm.util.UserTypeEnum;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.util.StringUtils;
  21. import org.springframework.web.bind.annotation.PostMapping;
  22. import org.springframework.web.bind.annotation.RequestBody;
  23. import org.springframework.web.bind.annotation.RequestMapping;
  24. import org.springframework.web.bind.annotation.RestController;
  25. import cn.binarywang.wx.miniapp.api.WxMaService;
  26. import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
  27. import javax.servlet.http.HttpServletRequest;
  28. import java.text.DateFormat;
  29. import java.text.SimpleDateFormat;
  30. import java.util.Date;
  31. import java.util.HashMap;
  32. import java.util.Map;
  33. /**
  34. * 鉴权服务
  35. */
  36. @Slf4j
  37. @RestController
  38. @RequestMapping("/wx/auth")
  39. public class WxAuthController {
  40. @Autowired
  41. private WxMaService wxService;
  42. @Autowired
  43. private WxUserService userService;
  44. /**
  45. * 微信登录
  46. *
  47. * @param wxLoginInfo
  48. * 请求内容,{ code: xxx, userInfo: xxx }
  49. * @param request
  50. * 请求对象
  51. * @return 登录结果
  52. */
  53. @PostMapping("login_by_weixin")
  54. public Object loginByWeixin(@RequestBody WxLoginInfo wxLoginInfo, HttpServletRequest request) {
  55. //客户端需携带code与userInfo信息
  56. String code = wxLoginInfo.getCode();
  57. UserInfo userInfo = wxLoginInfo.getUserInfo();
  58. if (code == null || userInfo == null) {
  59. return ResponseUtil.badArgument();
  60. }
  61. //调用微信sdk获取openId及sessionKey
  62. String sessionKey = null;
  63. String openId = null;
  64. try {
  65. long beginTime = System.currentTimeMillis();
  66. //
  67. WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(code);
  68. // Thread.sleep(6000);
  69. long endTime = System.currentTimeMillis();
  70. log.info("响应时间:{}",(endTime-beginTime));
  71. sessionKey = result.getSessionKey();//session id
  72. openId = result.getOpenid();//用户唯一标识 OpenID
  73. } catch (Exception e) {
  74. e.printStackTrace();
  75. }
  76. if (sessionKey == null || openId == null) {
  77. log.error("微信登录,调用官方接口失败:{}", code);
  78. return ResponseUtil.fail();
  79. }else{
  80. log.info("openId={},sessionKey={}",openId,sessionKey);
  81. }
  82. //根据openId查询wx_user表
  83. //如果不存在,初始化wx_user,并保存到数据库中
  84. //如果存在,更新最后登录时间
  85. WxUser user = userService.queryByOid(openId);
  86. if (user == null) {
  87. user = new WxUser();
  88. user.setUsername(openId);
  89. user.setPassword(openId);
  90. user.setWeixinOpenid(openId);
  91. user.setAvatar(userInfo.getAvatarUrl());
  92. user.setNickname(userInfo.getNickName());
  93. user.setGender(userInfo.getGender());
  94. user.setUserLevel((byte) 0);
  95. user.setStatus((byte) 0);
  96. user.setLastLoginTime(new Date());
  97. user.setLastLoginIp(IpUtil.client(request));
  98. user.setShareUserId(1);
  99. userService.add(user);
  100. } else {
  101. user.setLastLoginTime(new Date());
  102. user.setLastLoginIp(IpUtil.client(request));
  103. if (userService.updateById(user) == 0) {
  104. log.error("修改失败:{}", user);
  105. return ResponseUtil.updatedDataFailed();
  106. }
  107. }
  108. // token
  109. UserToken userToken = null;
  110. try {
  111. userToken = UserTokenManager.generateToken(user.getId());
  112. } catch (Exception e) {
  113. log.error("微信登录失败,生成token失败:{}", user.getId());
  114. e.printStackTrace();
  115. return ResponseUtil.fail();
  116. }
  117. userToken.setSessionKey(sessionKey);
  118. log.info("SessionKey={}",UserTokenManager.getSessionKey(user.getId()));
  119. Map<Object, Object> result = new HashMap<Object, Object>();
  120. result.put("token", userToken.getToken());
  121. result.put("tokenExpire", userToken.getExpireTime().toString());
  122. userInfo.setUserId(user.getId());
  123. if (!StringUtils.isEmpty(user.getMobile())) {// 手机号存在则设置
  124. userInfo.setPhone(user.getMobile());
  125. }
  126. try {
  127. DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
  128. String registerDate = df.format(user.getAddTime() != null ? user.getAddTime() : new Date());
  129. userInfo.setRegisterDate(registerDate);
  130. userInfo.setStatus(user.getStatus());
  131. userInfo.setUserLevel(user.getUserLevel());// 用户层级
  132. userInfo.setUserLevelDesc(UserTypeEnum.getInstance(user.getUserLevel()).getDesc());// 用户层级描述
  133. } catch (Exception e) {
  134. log.error("微信登录:设置用户指定信息出错:"+e.getMessage());
  135. e.printStackTrace();
  136. }
  137. result.put("userInfo", userInfo);
  138. log.info("【请求结束】微信登录,响应结果:{}", JSONObject.toJSONString(result));
  139. return ResponseUtil.ok(result);
  140. }
  141. /**
  142. * 绑定手机号码
  143. *
  144. * @param userId
  145. * @param body
  146. * @return
  147. */
  148. @PostMapping("bindPhone")
  149. public Object bindPhone(@LoginUser Integer userId, @RequestBody String body) {
  150. log.info("【请求开始】绑定手机号码,请求参数,body:{}", body);
  151. String sessionKey = UserTokenManager.getSessionKey(userId);
  152. String encryptedData = JacksonUtil.parseString(body, "encryptedData");
  153. String iv = JacksonUtil.parseString(body, "iv");
  154. WxMaPhoneNumberInfo phoneNumberInfo = null;
  155. try {
  156. phoneNumberInfo = this.wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
  157. } catch (Exception e) {
  158. log.error("绑定手机号码失败,获取微信绑定的手机号码出错:{}", body);
  159. e.printStackTrace();
  160. return ResponseUtil.fail();
  161. }
  162. String phone = phoneNumberInfo.getPhoneNumber();
  163. WxUser user = userService.selectByPrimaryKey(userId);
  164. user.setMobile(phone);
  165. if (userService.updateById(user) == 0) {
  166. log.error("绑定手机号码,更新用户信息出错,id:{}", user.getId());
  167. return ResponseUtil.updatedDataFailed();
  168. }
  169. Map<Object, Object> data = new HashMap<Object, Object>();
  170. data.put("phone", phone);
  171. log.info("【请求结束】绑定手机号码,响应结果:{}", JSONObject.toJSONString(data));
  172. return ResponseUtil.ok(data);
  173. }
  174. /**
  175. * 注销登录
  176. */
  177. @PostMapping("logout")
  178. public Object logout(@LoginUser Integer userId) {
  179. log.info("【请求开始】注销登录,请求参数,userId:{}", userId);
  180. if (userId == null) {
  181. return ResponseUtil.unlogin();
  182. }
  183. try {
  184. UserTokenManager.removeToken(userId);
  185. } catch (Exception e) {
  186. log.error("注销登录出错:userId:{}", userId);
  187. e.printStackTrace();
  188. return ResponseUtil.fail();
  189. }
  190. log.info("【请求结束】注销登录成功!");
  191. return ResponseUtil.ok();
  192. }
  193. }

application.yml文件中编写密钥

 

 测试结果如下

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/405158
推荐阅读
相关标签
  

闽ICP备14008679号