java实现微信小程序服务端(登录)

系统管理员 2021-01-10 06:32 820阅读 0赞

微信小程序如今被广泛使用,微信小程序按照微信官网的定义来说就是:

   微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。

   这就是微信小程序的魅力所在,有的时候我们不需要去下载过多的app,只要打开微信,就可以应用每一个服务,甚至连注册都变得简单起来,具有特别贴近人心的用户体验。

   最近在做一个微信小程序的服务端,主要就是实现登录、业务账号和微信号绑定的基本功能,接下来总结一下如何实现微信小程序的服务端代码。

   要去实现服务端的代码,就要先去了解客户端的请求。

   微信小程序开发平台开发了很全面、功能很强大的开发API供我们使用:

   https://developers.weixin.qq.com/miniprogram/dev/api/

   我们来看下api中的登录功能:

   1372758-20180713111904664-364330231.png

  这个是微信小程序登录的时序图,非常明显地告知了我们微信小程序登录的请求服务调用的过程

  1.添加微信小程序固定信息

  在注册的时候,这个小程序的appId和appSecret已经知道了,还有固定的url,然后我们可以将其做为配置文件放入后台的代码中去:

  1372758-20180713112137870-1020744254.png

  2.根据小程序信息和code获取openId和session_key

  在前端代码中,每当我们刚进入小程序的时候,都会去调用wx.login()方法,会得到一个code,然后发送给我们,然后,我们通过code和这些已知的参数,去调用微信的接口,去获取openId和session_key,作为登录态的标识

  

  1. /**
  2. * 获取微信小程序的session_key和openid
  3. *
  4. * @author hengyang4
  5. * @param code 微信前端login()方法返回的code
  6. * @return jsonObject
  7. *
  8. * */
  9. public JSONObject getSessionKeyAndOpenId(String code)throws Exception{
  10. //微信登录的code值
  11. String wxCode = code;
  12. //读取属性文件
  13. ResourceBundle resourceBundle = ResourceBundle.getBundle("weixin");
  14. //服务器端调用接口的url
  15. String requestUrl = resourceBundle.getString("url");
  16. //封装需要的参数信息
  17. Map<String,String> requestUrlParam = new HashMap<String,String>();
  18. //开发者设置中的appId
  19. requestUrlParam.put("appid",resourceBundle.getString("appId"));
  20. //开发者设置中的appSecret
  21. requestUrlParam.put("secret",resourceBundle.getString("appSecret"));
  22. //小程序调用wx.login返回的code
  23. requestUrlParam.put("js_code", wxCode);
  24. //默认参数
  25. requestUrlParam.put("grant_type", "authorization_code");
  26. JSONObject jsonObject = JSON.parseObject(sendPost(requestUrl,requestUrlParam));
  27. return jsonObject;
  28. }
  29. /**
  30. * 向指定 URL 发送POST方法的请求
  31. *
  32. * @param url 发送请求的 URL
  33. * @return 所代表远程资源的响应结果
  34. */
  35. public String sendPost(String url, Map<String, ?> paramMap) {
  36. PrintWriter out = null;
  37. BufferedReader in = null;
  38. String result = "";
  39. String param = "";
  40. Iterator<String> it = paramMap.keySet().iterator();
  41. while(it.hasNext()) {
  42. String key = it.next();
  43. param += key + "=" + paramMap.get(key) + "&";
  44. }
  45. try {
  46. URL realUrl = new URL(url);
  47. // 打开和URL之间的连接
  48. URLConnection conn = realUrl.openConnection();
  49. // 设置通用的请求属性
  50. conn.setRequestProperty("accept", "*/*");
  51. conn.setRequestProperty("connection", "Keep-Alive");
  52. conn.setRequestProperty("Accept-Charset", "utf-8");
  53. conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
  54. // 发送POST请求必须设置如下两行
  55. conn.setDoOutput(true);
  56. conn.setDoInput(true);
  57. // 获取URLConnection对象对应的输出流
  58. out = new PrintWriter(conn.getOutputStream());
  59. // 发送请求参数
  60. out.print(param);
  61. // flush输出流的缓冲
  62. out.flush();
  63. // 定义BufferedReader输入流来读取URL的响应
  64. in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
  65. String line;
  66. while ((line = in.readLine()) != null) {
  67. result += line;
  68. }
  69. } catch (Exception e) {
  70. log.error(e.getMessage(),e);
  71. }
  72. //使用finally块来关闭输出流、输入流
  73. finally{
  74. try{
  75. if(out!=null){
  76. out.close();
  77. }
  78. if(in!=null){
  79. in.close();
  80. }
  81. }
  82. catch(IOException ex){
  83. ex.printStackTrace();
  84. }
  85. }
  86. return result;
  87. }

  3. 将openId和session_key生成sessionId返回客户端

  1. 第三方服务器端拿到请求回来的session\_keyopenid,先留着,不能给客户端;然后用操作系统提供的真正随机数算法生成一个新的session,叫session\_id

· 所以,每次前端wx.login()后调用的服务端的controller我们就应该这样写:

  1. @RequestMapping(value = "/loginByWeixin", produces = "application/json;charset=UTF-8")
  2. public String loginByWeixin(@RequestParam("code") String code) throws Exception{
  3. //得到用户的openId + sessionKey
  4. JSONObject jsonObject = getSessionKeyAndOpenId(code);
  5. log.info(jsonObject.toString());
  6. System.out.println(jsonObject);
  7. String openId = jsonObject.getString("openid");
  8. String sessionKey = jsonObject.getString("session_key");
  9. //组装结果
  10. Map<String,Object> resMap = new HashMap<String,Object>();
  11. //判断openId是否存在用户表中
  12. UserInfo userInfo = userInfoMapper.selectByUserName(openId);
  13. if(ValidateUtil.isEmpty(userInfo)){
  14. //不存在该用户关联关系
  15. log.info("验证是否绑定微信","未登录");
  16. resMap.put("code",ErrorCode.ERR_WEIXIN_USER_EMPTY.getErrorCode());
  17. resMap.put("desc",ErrorCode.ERR_WEIXIN_USER_EMPTY.getErrorMessage());
  18. }else {
  19. //组装结果
  20. log.info("验证是否绑定微信", "用户查询成功");
  21. //0:操作成功
  22. resMap.put("code", ErrorCode.ERR_SUCCEED.getErrorCode());
  23. resMap.put("desc", ErrorCode.ERR_SUCCEED.getErrorMessage());
  24. resMap.put("userInfo", userInfo);
  25. }
  26. //将通过md5生成sessionId(一般是用个操作系统提供的真正随机数算法生成新的session)
  27. String sessionId = MD5.EncodeByMd5(openId+sessionKey+ DateUtil.getNowTime());
  28. jedisCache.hashSet(sessionId,"ses",openId);
  29. resMap.put("sessionId",sessionId);
  30. return JSONConvertor.toJSON(resMap);
  31. }

  4. 使用过滤器过滤请求头中含有session_id的请求

  然后我们将session_id为key,微信服务端返回的openId为值,保存起来,这里我们用了redis去缓存这个session信息,openId为我们系统用户与微信绑定的标识

  接下来,我们每次请求的时候,都会将session_id放入请求头中去,然后判断在redis中是否有key为该值得键值对,从而判断用户session是否失效

  我们这里使用了过滤器来拦截用户请求

  

  1. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException,ServletException{
  2. //设置跨域请求
  3. HttpServletResponse resp = (HttpServletResponse)response;
  4. resp.setHeader("Access-Control-Allow-Origin", "*");
  5. HttpServletRequest req = (HttpServletRequest)request;
  6. //获取请求时的sessionId
  7. String sessionId = req.getHeader("sessionId");
  8. if(StrUtil.IsNullOrEmpty(sessionId)){
  9. //该请求不需要验证session,直接通过
  10. log.info("sessionId过滤","该请求不需要过滤,通过");
  11. chain.doFilter(request,response);
  12. return;
  13. }else {
  14. //只有在缓存中存在该sessionId才能进行请求
  15. if (!jedisCache.existKey(sessionId)) {
  16. // 登录信息已过期,请重新登录
  17. log.info("sessionId过滤", "登录信息失效,请重新登录");
  18. response.getWriter().write("登录信息失效,请重新登录");
  19. return;
  20. }
  21. log.info("sessionId过滤", "session验证成功");
  22. chain.doFilter(request, response);
  23. }
  24. }

  5. 在数据库中建立用户与微信用户唯一标识的关联关系

  每当用户注册或者登陆时,请求中都会含有session_id,然后我们将session_id作为key去redis中查找,得到value值,也就是我们之前存的openId,然后我们将openId和用户信息进行数据库表中的关联,之后,我们调用登陆方法的时候,如果该openId有关联的用户信息,则不需要去登录,直接给前端返回用户信息即可,就是我们之前的那段代码:

1372758-20180713115000407-910463471.png

  

   在这里,我们的微信小程序服务端代码就基本实现了,可以用于微信小程序与业务系统的登录,微信小程序的功能还有很多,之后我们有机会多去试一下其他功能,感受小程序的强大和快捷。

发表评论

表情:
评论列表 (有 0 条评论,820人围观)

还没有评论,来说两句吧...

相关阅读

    相关 程序登录

    这段时间,一直闲,断断续续写了差不多10多篇博客了。今天下午研究了下微信小程序登录,以前没有做过这方面的,趁着有资源,玩一下小程序。 第一步: 去看微信开发文档接口,这个比什