【微信小程序开发】小程序微信用户授权登录(用户信息手机号)

news/2025/2/15 5:03:54/

🥳🥳Welcome Huihui's Code World ! !🥳🥳

接下来看看由辉辉所写的关于小程序的相关操作吧

目录

🥳🥳Welcome Huihui's Code World ! !🥳🥳

授权流程讲解

一.用户信息授权登录

1.wx.login

2.wx.getUserProfile

3.代码

WXML

JS

二.用户信息授权登录之后台交互

后端代码

WXML

JS

utils/user.js【封装的代码块】

三.手机号授权登录之后台交互

后端代码

WXML

JS


授权流程讲解

我们在使用微信中的小程序时,都会要我们进行授权,例如下面这样

那么这样的用户授权时怎么实现的呢,这一篇主要就是讲解用户授权登录的流程!!!

图片说明:

1.客户端调用 wx.login() 获取 临时登录凭证code,通过 wx.request() 发起网络请求,将 code 传给服务端
2、服务端使用 code + appid + appsecret 向微信换取 (调用 auth.code2Session 接口)用户唯一标识openid 会话密钥session_key
3、服务端自定义 登录状态token(与openid、session_key关联)返回客户端
4、客户端将 登录状态token 存入 缓存storage(推荐使用 wx.setStorageSync(‘key’, ‘value’) 同步存储)
5、客户端wx.request() 发起请求时,携带登录状态token (推荐使用 wx.getStorageSync(‘key’) 同步获取)
6、服务端通过 登录状态token 查询到对应 openid 和 session_key
7、验证成功后返回业务数据给客户端

一.用户信息授权登录

其中有两种方法,第一种方法是点击登录之后便直接获取了用户的个人信息,而第二种会询问用户是否同意授权,这样的话,会更具安全性

1.wx.login

这个方法主要用于获取用户的登录凭证(code)。在用户进入小程序时,前端会调用wx.login来获取这个code,然后将这个code发送给后台服务器。后台服务器再向微信发送请求,通过这个code来获取用户的唯一标识(openid)以及本次登录的会话密钥(session_key)。之后,后台服务器将这两个信息传回前台,用于自定义登录状态和用户唯一标识

2.wx.getUserProfile

这个方法主要用于获取用户的更多详细信息,如昵称、头像等。在使用这个方法之前,需要先调用wx.authorize接口来发起授权请求,请求用户授权提供这些信息。如果用户同意授权,就可以通过调用wx.getUserProfile方法来获取这些详细信息

3.代码

WXML

<!--pages/index/index.wxml-->
<view><button wx:if="{{canIUseGetUserProfile}}" type="primary" class="wx-login-btn" bindtap="getUserProfile">微信直接登录1</button><button wx:else open-type="getUserInfo" type="primary" class="wx-login-btn" bindgetuserinfo="wxLogin">微信直接登录2</button><image mode="scaleToFill" src="{{userInfo.avatarUrl}}" /><text>昵称:{{userInfo.nickName}}</text>
</view>

JS

// pages/index/index.js
Page({data: {userInfo: {},canIUseGetUserProfile: false,},onLoad() {// if (wx.getUserProfile) {//   this.setData({//     canIUseGetUserProfile: true//   })// }},getUserProfile(e) {console.log('getUserProfile')// 推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认// 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗wx.getUserProfile({desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写success: (res) => {console.log(res);this.setData({userInfo: res.userInfo,hasUserInfo: true})}})},wxLogin: function(e) {debuggerconsole.log('wxLogin')console.log(e.detail.userInfo);this.setData({userInfo: e.detail.userInfo})if (e.detail.userInfo == undefined) {app.globalData.hasLogin = false;util.showErrorToast('微信登录失败');return;}},/*** 生命周期函数--监听页面初次渲染完成*/onReady() {},/*** 生命周期函数--监听页面显示*/onShow() {},/*** 生命周期函数--监听页面隐藏*/onHide() {},/*** 生命周期函数--监听页面卸载*/onUnload() {},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh() {},/*** 页面上拉触底事件的处理函数*/onReachBottom() {},/*** 用户点击右上角分享*/onShareAppMessage() {}
})

用户授权登录后,后台便会保存用户的信息

二.用户信息授权登录之后台交互

前期准备

①准备数据接口

②密钥以及appid

后端代码

package com.zking.ssm.wxcontroller;/*** @Autho donkee* @Since 2022/6/27*/import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.alibaba.fastjson.JSONObject;
import com.zking.ssm.annotation.LoginUser;
import com.zking.ssm.model.UserInfo;
import com.zking.ssm.model.WxLoginInfo;
import com.zking.ssm.model.WxUser;
import com.zking.ssm.service.UserToken;
import com.zking.ssm.service.UserTokenManager;
import com.zking.ssm.service.WxUserService;
import com.zking.ssm.util.JacksonUtil;
import com.zking.ssm.util.ResponseUtil;
import com.zking.ssm.util.UserTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import javax.servlet.http.HttpServletRequest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;/*** 鉴权服务*/
@Slf4j
@RestController
@RequestMapping("/wx/auth")
public class WxAuthController {@Autowiredprivate WxMaService wxService;@Autowiredprivate WxUserService userService;/*** 微信登录** @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及sessionKeyString 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 idopenId = 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();}}// tokenUserToken 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);}}
}

WXML

<!--pages/auth/login/login.wxml-->
<view class="container"><view class="login-box"><button wx:if="{{canIUseGetUserProfile}}" type="primary" class="wx-login-btn" bindtap="getUserProfile">微信直接登录</button><button wx:else open-type="getUserInfo" type="primary" class="wx-login-btn" bindgetuserinfo="wxLogin">微信直接登录</button><button type="primary" class="account-login-btn" bindtap="accountLogin">账号登录</button></view>
</view>

JS

// pages/auth/login/login.js
var util = require('../../../utils/util.js');
var user = require('../../../utils/user.js');
const app = getApp();
Page({/*** 页面的初始数据*/data: {canIUseGetUserProfile: false, // 用于向前兼容lock:false},onLoad: function(options) {// 页面初始化 options为页面跳转所带来的参数// 页面渲染完成if (wx.getUserProfile) {this.setData({canIUseGetUserProfile: true})}//console.log('login.onLoad.canIUseGetUserProfile='+this.data.canIUseGetUserProfile)},/*** 生命周期函数--监听页面初次渲染完成*/onReady() {},/*** 生命周期函数--监听页面显示*/onShow() {},getUserProfile(e) {console.log('getUserProfile');// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认// 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗wx.getUserProfile({desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写success: (res) => {//console.log(res);user.checkLogin().catch(() => {user.loginByWeixin(res.userInfo).then(res => {app.globalData.hasLogin = true;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('微信登录失败');}});},wxLogin: function(e) {console.log('wxLogin');if (e.detail.userInfo == undefined) {app.globalData.hasLogin = false;util.showErrorToast('微信登录失败');return;}user.checkLogin().catch(() => {user.loginByWeixin(e.detail.userInfo).then(res => {app.globalData.hasLogin = true;wx.navigateBack({delta: 1})}).catch((err) => {app.globalData.hasLogin = false;if(err.errMsg=="request:fail timeout"){util.showErrorToast('微信登录超时');}else{util.showErrorToast('微信登录失败');}});});},accountLogin() {console.log('开发中....')}})

utils/user.js【封装的代码块】

/*** 用户相关服务*/
const util = require('../utils/util.js');
const api = require('../config/api.js');/*** Promise封装wx.checkSession*/
function checkSession() {return new Promise(function(resolve, reject) {wx.checkSession({success: function() {resolve(true);},fail: function() {reject(false);}})});
}
/*** 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);}});});
}
/*** 调用微信登录*/
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);})});
}/*** 判断用户是否登录*/
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);}});
}module.exports = {loginByWeixin,checkLogin,
};

三.手机号授权登录之后台交互

手机号授权登录的流程与用户信息授权登录流程是一样的,只不过向微信调用的接口有所不同

后端代码

package com.zking.ssm.wxcontroller;/*** @Autho donkee* @Since 2022/6/27*/import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.alibaba.fastjson.JSONObject;
import com.zking.ssm.annotation.LoginUser;
import com.zking.ssm.model.UserInfo;
import com.zking.ssm.model.WxLoginInfo;
import com.zking.ssm.model.WxUser;
import com.zking.ssm.service.UserToken;
import com.zking.ssm.service.UserTokenManager;
import com.zking.ssm.service.WxUserService;
import com.zking.ssm.util.JacksonUtil;
import com.zking.ssm.util.ResponseUtil;
import com.zking.ssm.util.UserTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import javax.servlet.http.HttpServletRequest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;/*** 鉴权服务*/
@Slf4j
@RestController
@RequestMapping("/wx/auth")
public class WxAuthController {/*** 绑定手机号码** @param userId* @param body* @return*/@PostMapping("bindPhone")public Object bindPhone(@LoginUser Integer userId, @RequestBody String body) {log.info("【请求开始】绑定手机号码,请求参数,body:{}", body);String sessionKey = UserTokenManager.getSessionKey(userId);String encryptedData = JacksonUtil.parseString(body, "encryptedData");String iv = JacksonUtil.parseString(body, "iv");WxMaPhoneNumberInfo phoneNumberInfo = null;try {phoneNumberInfo = this.wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);} catch (Exception e) {log.error("绑定手机号码失败,获取微信绑定的手机号码出错:{}", body);e.printStackTrace();return ResponseUtil.fail();}String phone = phoneNumberInfo.getPhoneNumber();WxUser user = userService.selectByPrimaryKey(userId);user.setMobile(phone);if (userService.updateById(user) == 0) {log.error("绑定手机号码,更新用户信息出错,id:{}", user.getId());return ResponseUtil.updatedDataFailed();}Map<Object, Object> data = new HashMap<Object, Object>();data.put("phone", phone);log.info("【请求结束】绑定手机号码,响应结果:{}", JSONObject.toJSONString(data));return ResponseUtil.ok(data);}}
}

WXML

<!--pages/ucenter/user/user.wxml-->
<form bindsubmit="formSubmit"><view class='personal-data'><view class='list'><view class='item acea-row row-between-wrapper'><view>头像</view><view class='pictrue'><image src='{{userInfo.avatarUrl}}'></image></view></view><view class='item acea-row row-between-wrapper'><view>名字</view><view class='input'><input type='text' disabled='true' name='nickname' value='{{userInfo.nickName}}'></input></view></view><view class='item acea-row row-between-wrapper'><view>手机号码</view><button name='phone' class='phoneW' value='{{userInfo.phone}}' wx:if="{{!userInfo.phone}}" bindgetphonenumber="getPhoneNumber" hover-class='none' open-type='getPhoneNumber'>点击获取</button><view class='input acea-row row-between-wrapper' wx:else><input type='text' disabled='true' name='phone' value='{{userInfo.phone}}' class='id'></input><text class='iconfont icon-suozi'></text></view></view><view class='item acea-row row-between-wrapper'><view>ID号</view><view class='input acea-row row-between-wrapper'><input type='text' value='1000{{userInfo.userId}}' disabled='true' class='id'></input><text class='iconfont icon-suozi'></text></view></view></view><button class='modifyBnt' bindtap="exitLogin">退 出</button></view>
</form>

JS

var util = require('../../../utils/util.js');
var api = require('../../../config/api.js');
var user = require('../../../utils/user.js');
var app = getApp();
Page({/*** 页面的初始数据*/data: {userInfo: {},hasLogin: false,userSharedUrl: ''},/*** 生命周期函数--监听页面加载*/onLoad: function (options) {},onShow: function () {let that = this;//获取用户的登录信息let userInfo = wx.getStorageSync('userInfo');this.setData({userInfo: userInfo,hasLogin: true});},getPhoneNumber: function (e) {console.log(e);let that = this;if (e.detail.errMsg !== "getPhoneNumber:ok") {// 拒绝授权return;}if (!this.data.hasLogin) {wx.showToast({title: '绑定失败:请先登录',icon: 'none',duration: 2000});return;}util.request(api.AuthBindPhone, {iv: e.detail.iv,encryptedData: e.detail.encryptedData}, 'POST').then(function (res) {if (res.errno === 0) {let userInfo = wx.getStorageSync('userInfo');userInfo.phone = res.data.phone;//设置手机号码wx.setStorageSync('userInfo', userInfo);that.setData({userInfo: userInfo,hasLogin: true});wx.showToast({title: '绑定手机号码成功',icon: 'success',duration: 2000});}});},exitLogin: function () {wx.showModal({title: '',confirmColor: '#b4282d',content: '退出登录?',success: function (res) {if (!res.confirm) {return;}util.request(api.AuthLogout, {}, 'POST');app.globalData.hasLogin = false;wx.removeStorageSync('token');wx.removeStorageSync('userInfo');wx.reLaunch({url: '/pages/index/index'});}})}
})

好啦,今天的分享就到这了,希望能够帮到你呢!😊😊  


http://www.ppmy.cn/news/1168519.html

相关文章

智能矩阵系统解决的问题?

智能矩阵系统可以解决的问题多种多样&#xff0c;它主要通过人工智能技术应用于矩阵系统&#xff0c;解决一些传统方法难以处理的问题。 以下是一些常见的应用场景&#xff1a; 1. 数据管理&#xff1a;智能矩阵系统可以有效地管理大量的数据&#xff0c;包括数据的存储、检索…

【JavaEE重点知识归纳】第9节:抽象类和接口

目录 一&#xff1a;抽象类 1.概念 2.语法 3.特性 4.作用 二&#xff1a;接口 1.概念 2.语法 3.接口使用 4.特性 5.实现多个接口 6.接口间的继承 7.Comparable接口 8.Clonable接口 9.抽象类和接口的区别 一&#xff1a;抽象类 1.概念 &#xff08;1&#xff0…

Kotlin中抽象类与接口

Kotlin 中的抽象类和接口是面向对象编程中的重要概念&#xff0c;它们提供了一种用于定义和组织代码的方式。在下面的代码示例中&#xff0c;我们将介绍 Kotlin 中的抽象类和接口&#xff0c;并给出相应的示例。 抽象类 抽象类是一种不能被实例化的类&#xff0c;它仅用作其他…

Go中的编程模式:Pipeline

本文章我们重点来介绍一下 Go 编程中的 Pipeline 模式。用过 Linux 命令行的人都不会陌生,它是一种把各种命令拼接起来完成一个更强功能的技术方法,在C语言中也有pipe管道的叫法,具体的有兴趣的同学也可以去了解。 现在的流式处理、函数式编程、应用网关对微服务进行简单的…

【量化交易笔记】10.建立最简单的交易策略

概述 量化说得简单一些用策略进行股票交易&#xff0c;在实施交易之前&#xff0c;需要制定策略&#xff0c;并回测试共效果 为了把交易说明清楚&#xff0c;将这个过程&#xff0c;能简单&#xff0c;就简单&#xff0c;总之&#xff0c;简单&#xff0c;简单再简单。 以下主…

计算机基础知识33

进程基础(操作系统中的概念) 进程它是操作系统总最重要的概念&#xff0c;线程也是 进程和线程都是有操作系统来调度使用的&#xff0c;我们程序员是不能控制的 # 进程和程序是两码事、完全不一样 程序&#xff1a;其实一个死的东西、一堆代码就是程序&#xff0c;它也没有生命…

智慧矿山矿山安全生产:皮带撕裂识别AI算法不用激光,能迅速识别皮带纵撕!

近些年来&#xff0c;智慧矿山在煤矿行业中发挥着越来越重要的作用。皮带的功能对于矿山运营至关重要&#xff0c;而皮带撕裂是造成生产中断、人身伤害等问题的重要原因之一。为了准确、及时地检测皮带撕裂的情况&#xff0c;AI算法的应用成为智慧矿山的关键。 ​​​​​​​…

Wireshark-win32-1.8.4 给winxp和win2003用

Index of /wireshark/win32/all-versions/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror https://mirrors4.tuna.tsinghua.edu.cn/wireshark/win32/all-versions/Wireshark-win32-1.12.1.exehttps://mirrors4.tuna.tsinghua.edu.cn/wireshark/win32/all-versions/W…