美文网首页小程序程序员
java实现微信小程序登录态维护

java实现微信小程序登录态维护

作者: f080beaba062 | 来源:发表于2017-09-30 16:26 被阅读960次
微信小程序

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

    本次就从最基本的微信小程序登录态维护开始吧。小程序官方api文档里面有对登录态的一个完整的解释,并且有相关的代码。想看详情,可以出门右转:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html#wxloginobject 我第一次看的时候没怎么看懂,并且代码没有提供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轻量级急速开发框架,非常高效,也推荐给大家。可能有哪些遗漏的地方欢迎大家积极提出意见和批评。

我是一名java开发者,喜欢研究一些新的技术,体验一些新的产品,如果喜欢这篇文章,也希望能转发一下。请注明一下出去就可以了。如果哪里不懂,也可以留言,或者加一下我的个人微信,也希望能交更多的朋友。

相关文章

  • java实现微信小程序登录态维护

        相信不少喜欢开发的朋友都已经知道微信小程序是个什么物种了,楼主也是从小程序内测期间就开始关注,并且也写过几...

  • 浅谈微信小程序登陆与Oauth

    参考: 从密码到token, 一个授权的故事 理解OAuth 2.0 小程序官方文档 微信小程序之登录态维护(十一...

  • 微信小程序登录开发

    本文主要介绍服务器端基于Java语言使用springmvc实现的微信小程序的登录开发。 登录功能是小程序必须的一个...

  • 微信小程序中用户登录和登录态维护

    提供用户登录以及维护用户的登录状态,是一个拥有用户系统的软件应用普遍需要做的事情。像微信这样的一个社交平台,如果做...

  • 小程序维护登录态

    一:何为登录态? 所谓登录态,就是程序在运行时,能够识别当前用户,能够证明自己的唯一性且合法。我们知道,WEB服务...

  • 小程序中的微信登录在安卓App中的写法

    使用uniApp将微信小程序移植到安卓App时,需要做一些改造,才可以实现微信登录。 微信小程序中的登录写法 其中...

  • 小程序 一键登录 uni

    实现小程序一键注册加登录实现逻辑:参考微信 首先调用微信的登录接口 wx.login,获取临时登录凭证 code。...

  • 微信小程序获取openId 和unionId 登录注册机制

    微信小程序的运行环境不是在浏览器下运行的。所以不能以cookie来维护登录态。下面我就来说说我根据官方给出的方法来...

  • 小程序(十八)小程序维护登录态

    现阶段小程序系列的最后一篇。 我们来看下小程序十如何维护登录态的,这个玩意,早应该说了,但是,直到我小程序做成现在...

  • 微信小程序保持登录态

    随着小程序的使用越来越广泛,公司也逐步开始了小程序项目的开发。本人作为公司开发小程序的试水员,必不可少的就是踩坑。...

网友评论

    本文标题:java实现微信小程序登录态维护

    本文链接:https://www.haomeiwen.com/subject/zhogextx.html