关于微信小程序登录的那些事


Posted in Javascript onJanuary 08, 2019

前言

最近团队在开发一款小程序,都是新手,一边看文档,一边开发。在开发中会遇到各种问题,今天把小程序登录这块的流程整理下,做个记录。

小程序的登录跟平时自己APP这种登录验证还不太一样,多了一个角色,那就是微信服务器。

关于微信小程序登录的那些事

根据微信官方提供的登录流程时序图可以清楚的了解小程序登录需要多少个步骤,下面我们来总结下:

  • 小程序启动,通过wx.login()获取code
  • 开发者服务器需要提供一个登录的接口,参数就是小程序获取的code
  • 登录接口收到code后,调用微信提供的接口进行code的验证
  • 得到验证结果,成功后能得到一个session_key和openid
  • 生成一个自定义的key, 将session_key和openid跟自定义的key关联起来
  • 将自定义的key返回给小程序
  • 每次请求都带上key, 后端根据key获取openid识别当前用户身份

首先code是微信给的,如果你随意生成code去验证肯定是无效的,只有微信给的code才有效。code传到开发者自己的服务后,再去问微信:

Hi 哥们,我这个code是有效的还是无效的啊?

微信会告诉你是有效还是无效,有效的情况下还会给你一个用户的标识,也就是openid,同时还会有一个sessionkey,也就是会话的key。sessionkey的有效期默认是2小时,当用户一直在使用小程序的话会自动刷新,这个是由微信这边来维护的。

注意:

  • 会话密钥 session_key 是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。
  • 临时登录凭证 code 只能使用一次

所以我们要为session_key创建别名,这个别名关联的哪个用户只有我们自己知道,唯一需要做的工作就在这块。

我推荐2种方式来做关联:

第一种:随机生成key, 关联openid,存入redis中,当请求带入key,直接从redis中获取openid得到当前用户信息,这个其实也就是我们自己去维护了会话信息

第二种:采用JWT生成token,将openid绑定到token中,将token返回给小程序,请求的时候带上token,通过解析token得到用户信息。

下面我们以第二种方式来进行讲解,会贴上部分代码:

小程序中在app.js中的onLaunch方法中增加获取code方法,并且调用后端的登录接口获取token:

wx.login({
 success: function (res) {
 var code = res.code;
 if (code) {
  console.log('app启动获取用户登录凭证:' + code);
  let params = { "code": code };
  let result = config.requestHttp(config.url.userLogin, 'POST', params)
  result.then(res => {
  let data = res.data
  if (data.code == 200) {
  wx.setStorageSync("login_token", data.data.token);
  }
  }).catch(err => {
  console.log(err)
  });
 } else {
  console.log('获取用户登录态失败:' + res.errMsg);
 }
 }
})

userLogin接口则根据小程序的code去调用微信接口验证:

// 小程序获取SessionKey接口地址
String loginUrl = "https://api.weixin.qq.com/sns/jscode2session";
String url = loginUrl + "?appid=%s&secret=%s&grant_type=%s&js_code=%s";
url = String.format(url, appid, appSecret, grantType, param.getCode());
String result = restTemplate.getForObject(url, String.class);
Map<String, Object> map = JsonUtils.toBean(Map.class, result);

// 请求成功
if (map.containsKey("session_key")) {
 String openid = map.get("openid").toString();
 // 第一次保存到用户表,生成JWT TOKEN返回
}

小程序端需要将 wx.request()封装成一个通用的方法,所有跟后台交互都用这个方法来调用接口,我们可以在这个方法中设置登录之后获取的Token。这样每次请求都会将Token塞到请求头中,我们在网关中就可以获取这个Token进行解析验证。

//请求封装
function requestHttp(url, method, data) {
 //请求头设置
 var header = {
 Authorization: wx.getStorageSync("login_token")
 }

 return new Promise((resolve, reject) => {
 wx.request({
  url: config.home_config + url,
  data: data,
  header: header,
  method: method,
  success: (res => {
  if (res.data.code === 200) {
   resolve(res)
  } else {
   reject(res)
  }
  }),

  fail: (res => {
  reject(res)
  })
 })
 })
}

Zuul中进行验证:

RequestContext ctx = RequestContext.getCurrentContext();
 HttpServletRequest request = ctx.getRequest();
 String token = request.getHeader("Authorization");

 if (StringUtils.isBlank(token)) {
   ctx.setSendZuulResponse(false);
   ctx.set("isSuccess", false);
   ctx.setResponseBody(JsonUtils.toJson(Response.fail("非法请求【缺少Authorization】", ResponseCode.NO_AUTH_CODE)));
   ctx.getResponse().setContentType("application/json; charset=utf-8");
   return null;
 }

 // 验证Token是否有效
 JWTResult jwResult = JWTUtils.checkToken(token);
 if (!jwResult.isStatus()) {
   ctx.setSendZuulResponse(false);
   ctx.set("isSuccess", false);
   ctx.setResponseBody(JsonUtils.toJson(Response.fail(jwResult.getMsg(), jwResult.getCode())));
   ctx.getResponse().setContentType("application/json; charset=utf-8");
   return null;
 }

 ctx.addZuulRequestHeader("loginUserId", jwResult.getUid());
 return null;

验证成功后将用户ID设置到请求头中,传递给后端服务使用。

使用JWT必然有一个问题是Token的失效问题,我这边失效时间设置的为2个小时,正常的话用户打开小程序,使用不可能连续超过2个小时,登录的逻辑是在app.js中做的,只要下次进去token就会重新申请。不过这个也可以调整,比如稍微长一点。

核心就是用户的认证交给了微信,只要微信告诉我们认证成功了,我们就可以自己接管会话信息了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
脚本吧 - 幻宇工作室用到js,超强推荐base.js
Dec 23 Javascript
Ext中下拉列表ComboBox组件store数据格式用法介绍
Jul 15 Javascript
基于JQuery打造无缝滚动新闻步骤详解
Mar 31 Javascript
Vue + Webpack + Vue-loader学习教程之功能介绍篇
Mar 14 Javascript
表格展示利器 Bootstrap Table实例代码
Sep 06 Javascript
详解React 在服务端渲染的实现
Nov 16 Javascript
浅谈node中的cluster集群
Jun 02 Javascript
vue-router 实现导航守卫(路由卫士)的实例代码
Sep 02 Javascript
vue v-for 使用问题整理小结
Aug 04 Javascript
node删除、复制文件或文件夹示例代码
Aug 13 Javascript
vue中axios的二次封装实例讲解
Oct 14 Javascript
jQuery实现移动端扭蛋机抽奖
Nov 08 jQuery
Vue2.x Todo之自定义指令实现自动聚焦的方法
Jan 08 #Javascript
关于React动态加载路由处理的相关问题
Jan 07 #Javascript
vue+iview 兼容IE11浏览器的实现方法
Jan 07 #Javascript
详解Vue iview IE浏览器不兼容报错(Iview Bable polyfill)
Jan 07 #Javascript
利用React Router4实现的服务端直出渲染(SSR)
Jan 07 #Javascript
Node.js EventEmmitter事件监听器用法实例分析
Jan 07 #Javascript
小程序二次贝塞尔曲线实现购物车商品曲线飞入效果
Jan 07 #Javascript
You might like
《神奇女侠:血脉》神力女超人大战犯罪公司
2020/04/09 欧美动漫
php获取目录所有文件并将结果保存到数组(实例)
2013/10/25 PHP
php使用smtp发送支持附件的邮件示例
2014/04/13 PHP
fireworks菜单生成器mm_menu.js在 IE 7.0 显示问题的解决方法
2009/10/20 Javascript
基于jQuery的树控件实现代码(asp.net+json)
2010/07/11 Javascript
js有关元素内容操作小结
2011/12/20 Javascript
深入理解JavaScript系列(14) 作用域链介绍(Scope Chain)
2012/04/12 Javascript
固定表格行列(expression)在IE下适用
2013/07/25 Javascript
JS 使用for循环遍历子节点查找元素
2014/09/06 Javascript
全面了解JavaScript的数据类型转换
2016/07/01 Javascript
Angular 4依赖注入学习教程之Injectable装饰器(六)
2017/06/04 Javascript
Nodejs 和Session 原理及实战技巧小结
2017/08/25 NodeJs
解决html-jquery/js引用外部图片时遇到看不了或出现403的问题
2017/09/22 jQuery
React SSR样式及SEO的实践
2018/10/22 Javascript
vue使用过滤器格式化日期
2021/01/20 Vue.js
[34:39]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#1COL VS EG第二局
2016/03/05 DOTA
Python中title()方法的使用简介
2015/05/20 Python
Python 爬虫图片简单实现
2017/06/01 Python
python计算列表内各元素的个数实例
2018/06/29 Python
解决每次打开pycharm直接进入项目的问题
2018/10/28 Python
CentOS 7下安装Python3.6 及遇到的问题小结
2018/11/08 Python
利用nohup来开启python文件的方法
2019/01/14 Python
Python实现最大子序和的方法示例
2019/07/05 Python
Python中 Global和Nonlocal的用法详解
2020/01/20 Python
Django如何使用redis作为缓存
2020/05/21 Python
python安装读取grib库总结(推荐)
2020/06/24 Python
python 中 .py文件 转 .pyd文件的操作
2021/03/04 Python
详解CSS3实现响应式手风琴效果
2020/06/10 HTML / CSS
皮姆斯勒语言学习:Pimsleur Language Programs
2018/06/30 全球购物
工程专业毕业生自荐信范文
2013/12/25 职场文书
茶叶店创业计划书范文
2014/01/19 职场文书
《陋室铭》教学反思
2014/02/26 职场文书
高中社区服务活动报告
2015/02/05 职场文书
2015年卫生监督工作总结
2015/05/21 职场文书
SpringBoot中获取profile的方法详解
2022/04/08 Java/Android
Python+SeaTable实现计算两个日期间的工作日天数
2022/07/07 Python