- 小程序登录微信登录接口演示
- 小程序授权登录理论
- 小程序授权登录代码演示
- 微信表情包存储问题
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)->重新尝试登录