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) { }, fail: function (error) { console.log("error:" + error); } })
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
|
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"); String new_key = DigestUtils.md5DigestAsHex((openid + session_key).getBytes()); this.jedis.hset(new_key, "NEW", session_key); this.jedis.expire(new_key, 300); 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
|
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 { 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