欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java实现微信小程序登录态维护的示例代码

程序员文章站 2024-02-26 20:28:22
相信不少喜欢开发的朋友都已经知道微信小程序是个什么物种了,楼主也是从小程序内测期间就开始关注,并且也写过几个已经上线的微信小程序。但是基本上都是写的纯前端,最近楼主从后端到...

相信不少喜欢开发的朋友都已经知道微信小程序是个什么物种了,楼主也是从小程序内测期间就开始关注,并且也写过几个已经上线的微信小程序。但是基本上都是写的纯前端,最近楼主从后端到前端写一个完整的小程序项目,中间碰到了一些问题,楼主会找一些个人觉得有学习价值的点不定时的拿出来跟大家分享,希望对你有一些帮助。

本次就从最基本的微信小程序登录态维护开始吧。小程序官方api文档里面有对登录态的一个完整的解释,并且有相关的代码。想看详情,可以出门右转: 我第一次看的时候没怎么看懂,并且代码没有提供java版本的,这让一个java程序员情何以堪,所以在努力研究了以后决定要做一个java版本的简单的demo放出来。

作为服务端,如果想获得到使用微信小程序的会员信息,就需要小程序作为客户端把会员的基本信息传过来。类似于手机号,openid可以作为当前小程序中用户的唯一性标志。然而如果把会员的openid信息明文直接在服务端与小程序端来回传输的话,会有安全性的问题。万一被别人得到这个openid,就相当于得到会员的手机号一样,就可以做一些其他操作了,显然是不安全的。

为了解决这一问题微信采用了相对安全的方式。

//app.js
app({
 onlaunch: function() {
  wx.login({
   success: function(res) {
    if (res.code) {
     //发起网络请求
     wx.request({
      url: 'https://test.com/onlogin',
      data: {
       code: res.code
      }
     })
    } else {
     console.log('获取用户登录态失败!' + res.errmsg)
    }
   }
  });
 }
})

微信小程序端会调用wx.login的api,然后会得到一个code,这个code对外人来讲是没有任何意义的,可以放心的传给服务端。服务端得到code以后,加上你申请小程序时的appid, app secret,去调微信的接口

https://api.weixin.qq.com/sns/jscode2session?appid=appid&secret=secret&js_code=jscode&grant_type=authorization_code

就可以得到以下参数:

  • openid 用户唯一标识
  • session_key 会话密钥
  • unionid 本字段在满足一定条件的情况下才返回

其中openid 就是会员的唯一性标记,此时服务端可以保存下来。

session_key 以后解密 unionid(整个开放平台会员的唯一性标识)时有用。

服务端得到openid以后,为了后边的交互,要保存下来。一般来讲有两种方式:一种是直接入数据库,一种是采用效率高一点的缓存。楼主采用的是后者,方式是redis。

按照微信的建议此时需要生成一个不重复值作为openid的唯一性标识。这里采用的是java的uuid。然后把这个uuid值作为key,把openid以及后面会用到的session_key作为value,存进redis。并且把uuid值返回给小程序。这样小程序就可以直接拿uuid值跟服务端交互。

也许会有人问,如果有人得到uuid值其实跟得到openid没什么区别啊,都相当于是会员的唯一性标志。

所以这里要对这个uuid值进行一个处理。首先存入redis时要有时效性。session_key在微信服务器有效期是30天,建议服务端缓存session_key不超过30天。当小程序传过来的uuid值过期时,认为这是过期的uuid,则重新走wx.login步骤。

为了方便redis中不仅会寸uuid与openid的对应关系。还会再存一条openid对应uuid的记录,目的是为了下一次重新wx.login步骤时根据openid找到之前老的uuid,如果存在的话就删掉,然后查询一条新的uuid值,并且把openid对应的这条记录也更新掉。这样redis服务器中就不会有多余的脏数据,减轻服务器的负担。

以上就是我理解的整个登录态的过程,当然还有wx.checksession这些没有讲到,其实就是发现session_key失效是再重新走一遍上述的流程就可以了。所以没有仔细说。不知道我有没有讲清楚。我会把整个流程的关键代码贴出来,供大家参考。

@actionkey("/loginbyweixin")
  public void loginbyweixin() throws exception {
    logger.info("start getsessionkey");
    string json = httpkit.readdata(getrequest());
    jsonobject reqjson = json.parseobject(json);
    string jscode = reqjson.getstring("code");
    if (jscode == null || "".equals(jscode)) {
      logger.info("缺少必要参数");
      renderjson(new outroot().setcode("100").setmsg(sys.parameter_fail));
    } else {
      list<record> record = appinfoservice.selectappinfo();
      string appid = record.get(0).get("app_id");
      string appsecret = record.get(0).getstr("app_secret");
      if (appid == null || "".equals(appid) || appsecret == null || "".equals(appsecret)) {
        logger.info("缺少必要参数");
        renderjson(new outroot().setcode("100").setmsg(sys.parameter_fail));
      } else {
        string url = "https://api.weixin.qq.com/sns/jscode2session";
        string httpurl = url + "?appid=" + appid + "&secret=" + appsecret + "&js_code=" + jscode
            + "&grant_type=authorization_code";
        string ret = httprequest.sendgetrequest(httpurl);
        logger.info("微信返回的结果 {}", ret);
        if (ret == null || "".equals(ret)) {
          logger.info("网络超时");
          renderjson(new outroot().setcode("101").setmsg(sys.contact_fail));
        } else {
          jsonobject obj = jsonobject.parseobject(ret);
          if (obj.containskey("errcode")) {
            string errcode = obj.get("errcode").tostring();
            logger.info("微信返回的错误码{}", errcode);
            renderjson(new outroot().setcode("101").setmsg(sys.contact_fail));
          } else if (obj.containskey("session_key")) {
            logger.info("调微信成功");
            // 开始处理userinfo
            string openid = obj.get("openid").tostring();
            record tbmember = new record();
            tbmember.set("weixin_openid", openid);
            system.out.println("openid==" + openid);
            // 先查询openid存在不存在,存在不入库,不存在就入库
            list<record> memberlist = tbmemberservice.selectmember(tbmember);
            if (memberlist != null && memberlist.size() > 0) {
              logger.info("openid已经存在,不需要插入");
            } else {
              jsonobject rawdatajson = reqjson.getjsonobject("userinfo");
              string nickname = rawdatajson.getstring("nickname");
              string avatarurl = rawdatajson.getstring("avatarurl");
              string gender = rawdatajson.getstring("gender");
              string province = rawdatajson.getstring("province");
              string city = rawdatajson.getstring("city");
              string country = rawdatajson.getstring("country");
              tbmember.set("gender", gender);
              tbmember.set("nick_name", nickname);
              tbmember.set("avatar_url", avatarurl);
              long openid2 = tbmemberservice.addmember(tbmember);
              logger.info("openid不存在,插入数据库");
            }
            // (1) 获得sessionkey
            string sessionkey = obj.get("session_key").tostring();
            logger.info("sessionkey==" + sessionkey);
            logger.info("openid==" + openid);
            // (2) 得到sessionkey以后存到缓存,key值采用不会重复的uuid
            string rsession = uuid.randomuuid().tostring();
            cache tokencache = redis.use("redis_00");
            // (3) 首先根据openid,取出来之前存的openid对应的sessionkey的值。
            string oldseesionkey = tokencache.getjedis().get(openid);
            if (oldseesionkey != null && !"".equals(oldseesionkey)) {
              logger.info("oldseesionkey==" + oldseesionkey);
              // (4) 删除之前openid对应的缓存
              tokencache.getjedis().del(oldseesionkey);
              logger.info("老的openid删除以后==" + tokencache.getjedis().get(oldseesionkey));
            }
            // (5) 开始缓存新的sessionkey: key --> uuid, value --> sessionobj
            jsonobject sessionobj = new jsonobject();
            sessionobj.put("openid", openid);
            sessionobj.put("sessionkey", sessionkey);
            tokencache.getjedis().set(rsession, sessionobj.tojsonstring());

            // (6) 开始缓存新的openid与session对应关系 : key --> openid , value --> rsession
            tokencache.getjedis().set(openid, rsession);

            string newopenid = tokencache.getjedis().get(openid);
            string newrsession = tokencache.getjedis().get(rsession);
            logger.info("新的openid==" + newopenid);
            logger.info("新的newrsession==" + newrsession);
            // (7) 把新的sessionkey返回给小程序
            jsonobject objret = new jsonobject();
            objret.put("rdsessionkey", rsession);
            objret.put("errno", 0);
            renderjson(objret);
          }

        }
      }
    }
  }

项目框架是我比较喜欢jfinal,java轻量级急速开发框架,非常高效,也推荐给大家。可能有哪些遗漏的地方欢迎大家积极提出意见和批评。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。