- 小程序登录微信登录接口演示
- 小程序授权登录理论
- 小程序授权登录代码演示
- 微信表情包存储问题
1.小程序登录微信登录接口演示
推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
// 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) { debugger console.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() { } })
<!--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>
2.小程序授权登录理论
小程序:小程序对应的项目,自己写的前端
临时的code,是一个临时的字符串
开发者服务器;小程序后台接口,自己写的后端
appid:是指小程序相对于微信软件的唯一标识
微信接口服务:微信的接口服务器,不是我们自己写的代码(看成阿里云的短信服务)
session_key:指的是当前的登录请求,指的是一次会话
openid:登录的用户(javaxl),相当于微信小程序这款软件的唯一标识
storage:看成vue中vuex
3.小程序授权登录代码演示
//oa-mini\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.zlj.ssm.wxcontroller; /** * @Autho donkee * @Since 2022/6/27 */ import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; import com.alibaba.fastjson.JSONObject; import com.zlj.ssm.annotation.LoginUser; import com.zlj.ssm.model.UserInfo; import com.zlj.ssm.model.WxLoginInfo; import com.zlj.ssm.model.WxUser; import com.zlj.ssm.service.UserToken; import com.zlj.ssm.service.UserTokenManager; import com.zlj.ssm.service.WxUserService; import com.zlj.ssm.util.JacksonUtil; import com.zlj.ssm.util.ResponseUtil; import com.zlj.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 { @Autowired private WxMaService wxService; @Autowired private 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及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); } /** * 绑定手机号码 * * @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); } /** * 注销登录 */ @PostMapping("logout") public Object logout(@LoginUser Integer userId) { log.info("【请求开始】注销登录,请求参数,userId:{}", userId); if (userId == null) { return ResponseUtil.unlogin(); } try { UserTokenManager.removeToken(userId); } catch (Exception e) { log.error("注销登录出错:userId:{}", userId); e.printStackTrace(); return ResponseUtil.fail(); } log.info("【请求结束】注销登录成功!"); return ResponseUtil.ok(); } }
// // 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(); }
package com.zlj.ssm.wxcontroller; import java.util.HashMap; import java.util.Map; import com.zlj.ssm.annotation.LoginUser; import com.zlj.ssm.model.WxUser; import com.zlj.ssm.service.WxUserService; import com.zlj.ssm.util.ResponseUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; /** * 用户服务 */ @Slf4j @RestController @RequestMapping("/wx/user") @Validated public class WxUserController { @Autowired private WxUserService userService; /** * 用户个人页面数据 * <p> * @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); } }
4.微信表情包存储问题
工具->多账号调试->测试号(熊猫)->个人中心->点击登录->微信直接登录->允许(直接这样会报错,需要将MySQL安装的地方,将里面my.ini的utf8修改为utf8mb4,并且重启服务里的mysql)->重新尝试登录