七仔的博客

七仔的博客GithubPages分博

0%

Spring MVC实现微信小程序登录流程

Spring MVC实现微信小程序登录流程

Spring MVC实现微信小程序登录流程

流程说明:

1.小程序调用 wx.qy.login() 获取 临时登录凭证code ,并回传到服务商服务器。

2.服务商服务器以code换取 用户唯一标识 userid 、用户所在企业corpid 和 会话密钥 session_key。

此步骤以后服务商后台可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。

流程

Spring MVC实现登录流程:

微信小程序的首页需要实现该流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
var that = this;
// 登录
wx.login({
success: function (res) {
if (res.code) {
wx.request({
url: app.globalData.path + "ConferenceNotes/login",
data: {
code: res.code
},
method: "POST",
header: {
'content-type': 'application/json',
},
success: function (res) {
var token = res.data;
wx.getUserInfo({
success: res => {
// 保存用户信息到服务端
wx.request({
url: app.globalData.path + "ConferenceNotes/getUserInfo?new_key=" + token + "&email=" + that.data.email,
data: res,
method: "POST",
header: {
'Authorization': 'Bearer ' + token,
'content-type': 'application/json',
},
success: function (res) {
//res.data应该有你返回的服务器对用户唯一标识(不是openID)
},
fail: function (error) {
console.log("error:" + error);
}
})

// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (app.userInfoReadyCallback) {
app.userInfoReadyCallback(res)
}
}
})

},
fail: function (error) {
console.log(error);
}
})
} else {
console.log("error code " + res.errMsg);
}
}
})

Spring MVC响应login请求:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 登录
*/
@ResponseBody
@RequestMapping("/login")
public void login(HttpServletResponse response,@RequestBody Code codeObject) throws IOException {
response.setHeader("Access-Control-Allow-Origin", "*");
String code = codeObject.getCode();
String new_key = this.userService.getNewKey(code);
response.getWriter().write(new_key);
response.getWriter().close();
}

调用Service层的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 获取新的key,此key保存5分钟
*/
public String getNewKey(String code){
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=wx0805ed56c68e316b&secret="
+ "41f765c3adc892684c5a7ccb378e6c3a&js_code=" + code + "&grant_type=authorization_code";
JSONObject jsonObject = JSON.parseObject( UrlUtil.sendPost( url,"" ));
String openid = (String) jsonObject.get("openid");
String session_key = (String) jsonObject.get("session_key");
//根据openid和session_key计算出来个值保存到reids并设置5分钟的过期时间
String new_key = DigestUtils.md5DigestAsHex((openid + session_key).getBytes());
this.jedis.hset(new_key, "NEW", session_key);
this.jedis.expire(new_key, 300);//5分钟过期
return new_key;
}

这里我使用Redis进行保存,并设置5分钟的过期时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 获取用户信息
*/
@ResponseBody
@RequestMapping("/getUserInfo")
public void test(HttpServletRequest request, HttpServletResponse response,@RequestBody UserData userData) throws IOException {
request.setCharacterEncoding("UTF-8");
response.setHeader("Access-Control-Allow-Origin", "*");
String new_key = request.getParameter("new_key");
String email = request.getParameter("email");
Message message = this.userService.getUserInfo(new_key, email, userData);
ObjectMapper mapper = new ObjectMapper();
response.getWriter().write(mapper.writeValueAsString(message));
response.getWriter().close();
}

继续响应getUserInfo请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Override
public Message getUserInfo(String new_key, String email, UserData userData) {
Message message = new Message();
if(new_key != null && !new_key.equals("")){
String session_key = this.jedis.hget(new_key, "NEW");
if(session_key != null && !session_key.equals("")){
this.jedis.hdel(new_key, "NEW");
String iv = userData.getIv();
String encryptedData = userData.getEncryptedData();
JSONObject userInfoJSON = getUserInfoJSON(encryptedData, session_key, iv);
if(userInfoJSON != null){
UserInfo userInfo = JSON.parseObject(userInfoJSON.toJSONString(),UserInfo.class);
userInfo.setAvatarUrl(userInfoJSON.getString("avatarUrl"));
userInfo.setEmail("");
if(email == null || email.equals("")){
UserInfo userInfo1 = this.userDao.selectUser(userInfo.getOpenId());
if(userInfo1 == null){
message.setMessage("no email");
}
else{
userInfo = userInfo1;
message.setMessage(userInfo1.getEmail());
}

}
else {
userInfo.setEmail(email);
message.setMessage(email);
}
System.out.println("before:" + userInfo.toString());
userInfo = login(userInfo);
System.out.println("next:" + userInfo.toString());
message.setState("success");
message.setCode(userInfo.getId().toString());
}else {
message.setMessage("getUserInfo Algorithm error");
}
}else {
message.setMessage("no session_key");
}
}else {
message.setMessage("no new_key");
}
return message;
}

实际上我这个写的很不好,后面会再修改

调用了三个函数

login:

1
2
3
4
5
6
7
8
9
10
private UserInfo login(UserInfo userInfo){
UserInfo userInfo_r = this.userDao.selectUser(userInfo.getOpenId());
if(userInfo_r == null)
this.userDao.insertUser(userInfo);
else{
this.userDao.updateUser(userInfo);
userInfo.setId(userInfo_r.getId());
}
return userInfo;
}

getUserInfoJson:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 获取UserInfo信息
*/
private JSONObject getUserInfoJSON(String encryptedData, String sessionkey, String iv){
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 + 1;
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 = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
AlgorithmParameters parameters = AlgorithmParameters.getInstance("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, StandardCharsets.UTF_8);
return JSONObject.parseObject(result);
}
} catch (NoSuchAlgorithmException | InvalidParameterSpecException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchProviderException e) {
e.printStackTrace();
}
return null;
}

还有一个是从数据库调数据的,这里就不展示了

我写这篇文章主要是给你们一个大概的流程和思路,里面的有些通用函数可以拿去用,但是最好不要照搬我的所有代码,因为时间紧,所以代码质量不怎么地,后面会继续修改更新博客的。

此为博主副博客,留言请去主博客,转载请注明出处:https://www.baby7blog.com/myBlog/25.html

欢迎关注我的其它发布渠道