(⼗)、SpringBoot整合⼩程序登录
(⼗)、SpringBoot整合⼩程序登录
1. ⼩程序登录流程
⼩程序登录流程涉及到三个⾓⾊:⼩程序、开发者服务器、服务器
三者交互步骤如下:
第⼀步:⼩程序通过wx.login()获取code。
第⼆步:⼩程序通过wx.request()发送code到开发者服务器。
第三步:开发者服务器接收⼩程序发送的code,并携带appid、appsecret(这两个需要到⼩程序后台查看)、code发送到服务器。
第四步:服务器接收开发者服务器发送的appid、appsecret、code进⾏校验。校验通过后向开发者服务器发送session_key、openid。
第五步:开发者服务器⾃⼰⽣成⼀个skey(⾃定义登录状态)与openid、session_key进⾏关联,并存到
数据库中(mysql、redis等)。
第六步:开发者服务器返回⽣成skey(⾃定义登录状态)到⼩程序。
第七步:⼩程序存储skey(⾃定义登录状态)到本地。
第⼋步:⼩程序通过wx.request()发起业务请求到开发者服务器,同时携带skey(⾃定义登录状态)。
第九步:开发者服务器接收⼩程序发送的skey(⾃定义登录状态),查询skey在数据库中是否有对应的openid、session_key。
第⼗步:开发者服务器返回业务数据到⼩程序。
yml:
<!--hutool具包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.0</version>
</dependency>
<!--简化代码的⼯具包-->
springboot原理流程
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--  mybatis-plus-spring-boot-starter-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
wx返回的⽤户信息:
/**
* @Author dw
* @ClassName WeChatUserInfo
* @Description ⽤户信息
* @Date 2020/8/28 14:14
* @Version 1.0
*/
@Data
* 返回的code
*/
private String code;
/**
* ⾮敏感的⽤户信息
*/
private String rawData;
/**
* 签名信息
*/
private String signature;
/**
* 加密的数据
*/
private String encrypteData;
/**
* 加密密钥
*/
private String iv;
}
WeChatUtil⼯具:
/
**
* @Author dw
* @ClassName WeChatUtil
* @Description
* @Date 2020/8/28 10:56
* @Version 1.0
*/
public class WeChatUtil {
public static JSONObject getSessionKeyOrOpenId(String code) {
String requestUrl = "api.weixin.qq/sns/jscode2session";
HashMap<String, Object> requestUrlParam = new HashMap<>();
/
/⼩程序appId
requestUrlParam.put("appid", "⼩程序appId");
//⼩程序secret
requestUrlParam.put("secret", "⼩程序secret");
//⼩程序端返回的code
requestUrlParam.put("js_code", code);
//默认参数
requestUrlParam.put("grant_type", "authorization_code");
//发送post请求读取调⽤接⼝获取openid⽤户唯⼀标识
String result = (requestUrl, requestUrlParam);
JSONObject jsonObject = JSONUtil.parseObj(result);
return jsonObject;
}
public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) throws Base64DecodingException { // 被加密的数据
byte[] dataByte = Base64.decode(encryptedData);
// 加密秘钥
byte[] keyByte = Base64.decode(sessionKey);
// 偏移量
byte[] ivByte = Base64.decode(iv);
try {
// 如果密钥不⾜16位,那么就补⾜.  这个if 中的内容很重要
int base = 16;
if (keyByte.length % base != 0) {
int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
byte[] temp = new byte[groups * base];
Arrays.fill(temp, (byte) 0);
System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
keyByte = temp;
}
// 初始化
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Instance("AES/CBC/PKCS7Padding", "BC");
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
AlgorithmParameters parameters = Instance("AES");
parameters.init(new IvParameterSpec(ivByte));
// 初始化
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
byte[] resultByte = cipher.doFinal(dataByte);
if (null != resultByte && resultByte.length > 0) {
String result = new String(resultByte, "UTF-8");
return JSONUtil.parseObj(result);
}
} catch (Exception e) {
登录controller:
/
**
* @Author dw
* @ClassName WeChatUserLoginController
* @Description
* @Date 2020/8/28 14:12
* @Version 1.0
*/
@RestController
public class WeChatUserLoginController {
@Resource
private IUserService userService;
/
**
* ⽤户登录详情
*/
@PostMapping("wx/login")
public ResultInfo user_login(@RequestBody WeChatUserInfo weChatUserInfo) throws Base64DecodingException { // 2.开发者服务器登录凭证校验接⼝ appId + appSecret + 接收⼩程序发送的code
JSONObject SessionKeyOpenId = Code());
// 3.接收接⼝服务获取返回的参数
String openid = ("openid", String.class);
String sessionKey = ("session_key", String.class);
// ⽤户⾮敏感信息:rawData
// 签名:signature
JSONObject rawDataJson = JSONUtil.RawData());
// 4.校验签名⼩程序发送的签名signature与服务器端⽣成的签名signature2 = sha1(rawData + sessionKey)
//  String signature2 = DigestUtils.RawData() + sessionKey);
// if (!Signature().equals(signature2)) {
//  ( "签名校验失败");
//}
//encrypteData⽐rowData多了appid和openid
JSONObject userInfo = EncrypteData(),
sessionKey, Iv());
/
/ 5.根据返回的User实体类,判断⽤户是否是新⽤户,是的话,将⽤户信息存到数据库;不是的话,更新最新登录时间        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.lambda().eq(User::getLoginName, openid);
int userCount = unt(userQueryWrapper);
// uuid⽣成唯⼀key,⽤于维护⼩程序⽤户与服务端的会话(或者⽣成Token)
String skey = UUID.randomUUID().toString();
if (userCount <= 0) {
// ⽤户信息⼊库
String nickName = ("nickName",String.class);
String avatarUrl = ("avatarUrl",String.class);
String gender = ("gender",String.class);
String city = ("city",String.class);
String country = ("country",String.class);
String province = ("province",String.class);
// 新增⽤户到数据库
} else {
// 已存在,更新⽤户登录时间
}
//6. 把新的skey返回给⼩程序
return ResultInfo.success();
}
}
全局返回结果:
public class ResultInfo {
/**
* 响应代码
*/
private String code;
/**
* 响应消息
*/
private String message;
private Object result;
public ResultInfo() {
}
public ResultInfo(BaseErrorInfoInterface errorInfo) {
}
public String getCode() {
return code;
}
public void setCode(String code) {
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
}
/**
* 成功
*
* @return
*/
public static ResultInfo success() {
return success(null);
}
/**
* 成功
* @param data
* @return
*/
public static ResultInfo success(Object data) {
ResultInfo rb = new ResultInfo();
rb.setCode(ResultCode());
rb.setMessage(ResultMsg());        rb.setResult(data);
return rb;
}
/**
* 失败
*/
public static ResultInfo error(BaseErrorInfoInterface errorInfo) {        ResultInfo rb = new ResultInfo();
rb.ResultCode());
rb.ResultMsg());
rb.setResult(null);
return rb;
}
/**
* 失败
*/
public static ResultInfo error(String code, String message) {        ResultInfo rb = new ResultInfo();
rb.setCode(code);
rb.setMessage(message);
rb.setResult(null);
return rb;
}
/**
* 失败
*/
rb.setCode("-1");
rb.setMessage(message);
rb.setResult(null);
return rb;
}
}
4. ⼩程序
4.1 初始配置
初始配置
4.2 me.wxml
<view class="container">
<!-- 登录组件 developers.weixin.qq/miniprogram/dev/UserInfo.html -->
<button wx:if="{{!hasUserInfo}}" open-type="getUserInfo" bind:getuserinfo="onGetUserInfo">授权登录</button>  <!-- 登录后使⽤open-data -->
<view class="avatar-container avatar-position">
<image src="{{userInfo.avatarUrl}}" wx:if="{{hasUserInfo}}" class="avatar" />
<open-data wx:if="{{hasUserInfo}}" type="userNickName"></open-data>
</view>
</view>
4.3 me.wxss
4.4 me.json
{
}
4.5 me.js
// pages/me/me.js
Page({
/**
* 页⾯的初始数据
*/
data: {
hasUserInfo: false,
userInfo: null
},
onLoad: function() {
// 页⾯加载时使⽤⽤户授权逻辑,弹出确认的框
this.userAuthorized()
},
userAuthorized() {
success: data => {
if (data.authSetting['scope.userInfo']) {
success: data => {
this.setData({
hasUserInfo: true,
userInfo: data.userInfo
})
}
})
} else {
this.setData({

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。