thinkjs微信中控之微信鉴权登陆的实现代码


Posted in Javascript onAugust 08, 2019

前言

上一篇文章大概写了一下如何搭一个微信中控服务: 【thinkjs搭建微信中控服务】 。

接下来这篇,专门写一下如何在此基础上扩展出来一个比较好用的微信鉴权登陆的方案。

由于这一段的逻辑着实有点绕,所以就单独拿出来写了。

有时候,调用方甚至可以通过这个方案,进行多公众号openid的之间的关联。

官方说明

开发文档

微信文档地址:传送门

鉴权逻辑

  • 前端跳转到以下url,重定向或者代码跳转都可以:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
  • 弹出是否同意授权的框,用户同意授权(如果是静默授权,就不会弹出同意框),然后页面会重定向到上面链接的redirect_uri地址(一般是开发者处理下一步鉴权逻辑的服务端API),并且会带上code参数。
  • 服务端拿到code之后,调用以下api来获取网页授权的access_token和用户的openid:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

拿到openid之后,理论上鉴权的逻辑就算完成了。

开发者可以继续用openid和access_token去获取用户信息;或者进行一些其他的业务流程。

具体的参数说明看微信的官方文档就可以了。

中控逻辑

第一步:页面跳转至中控API

业务调用方会有自己的登陆逻辑,只需要获取到当前调用接口的用户的openid,然后再进行接下来的业务逻辑即可。

前端调用业务接口的时候,如果服务端发现当前访问用户没有登陆状态,就会告诉前端需要鉴权,并且把需要跳转的中控API链接响应给前端。

然后前端就开始往中控的API链接跳转。

第二步:中控重定向到微信API

相关代码

// 接口 - 鉴权获取code
async go_authAction() {
  let that = this;
  let {back, serve = ''} = that.get();
  if (think.isEmpty(back)) {
    return that.json({code: 1, msg: '参数不正确'})
  }
  let newBack = encodeURIComponent(back);
  let redirectUri = `${baseHost}/api/open/wx/login_wechat?${encodeURIComponent(`back=${newBack}&wxid=${that.wxConfig.id}&serve=${serve}`)}`;
  let url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${that.wxConfig.appid}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`
  that.redirect(url);
}

作用:

鉴权获取code

地址:

baseHost + /open/wx/go_auth

参数:

参数名 必选 说明
wxid 对应配置公众号的id,告诉中控用哪个公众号鉴权
back 跳转到鉴权链接之前的页面完整url,便于鉴权完毕后重定向回之前页面
serve 调用方api回调地址,在鉴权逻辑完成后,会携带openid重定向回这个地址

描述:

我这里默认都是静默授权。

在这里可以看到代码里面,中控把调用方传过来的 wxid , back 和 serve 三个参数拼接到了微信API的回调链接 redirect_uri 里面。

第三步:微信回调中控API

相关代码

async login_wechatAction() {
  let that = this;
  let {code, back, serve = ''} = that.get();
  if (think.isEmpty(code) || think.isEmpty(back)) {
    return that.json({code: 1, msg: '参数不正确'})
  }
  let newBack = encodeURIComponent(back);
  let apiWxController = that.controller('private/wx');
  let openid = await that._getOpenIdByAuthCode(that.wxConfig.id, code);
  let backUrl = `${serve}?wxid=${that.wxConfig.id}&openid=${openid}&redirect=${newBack}`;
  that.redirect(backUrl);
}

_getOpenIdByAuthCode(wxid, code){
  let that = this;
  let {appid, secret} = await that.controller('common').getWxConfigById(wxid);
  let {data} = await axios({
    method: 'get',
    url: `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appid}&secret=${secret}&code=$[code]&grant_type=authorization_code`
  })
  return data.openid
}

作用:

通过微信回调传回来的code,获取openid

地址:

baseHost + /open/wx/login_wechat

参数:

参数名 必选 说明
wxid 对应配置公众号的id,告诉中控用哪个公众号鉴权
code 微信回传的code
back 跳转到鉴权链接之前的页面完整url,便于鉴权完毕后重定向回之前页面(上一步拼接的)
serve 调用方api回调地址,在鉴权逻辑完成后,会携带openid重定向回这个地址(上一步拼接的)

描述:

这里中控拿到code之后,去获取openid。 获取完之后,重定向回 serve (业务系统)地址,并把获取到的 openid 和 back 作为参数传回去

第四步:业务系统自行处理

接下来业务系统就能通过开放的回调地址(上面的 serve ),来拿到以下信息:

  • openid (微信ID),
  • redirect (上面的 back ,最初用户在前端调用接口的页面地址)

这时候就能用这个openid去处理自己的登陆逻辑,比如获取用户信息,缓存session保存登陆状态之类的。

然后再重定向回 back 地址,也就是用户在鉴权之前访问的页面。

鉴权结束

简单说就是以下逻辑

  • 前端 调用 业务接口 发现没有登陆状态,告诉前端往中控跳!
  • 前端 跳转至 中控API 拼接接下来要回调的参数
  • 中控 重定向至 微信API 获取code
  • 微信 重定向至 中控API 获取openid
  • 中控 重定向回 业务回调API 拿到openid,保存用户登陆状态
  • 业务 重定向回 前端
  • 前端 调用 业务接口 发现有登陆状态了,完事儿

虽然历经的跳转和重定向看起来很多,但是实际用起来,其实是很快的,用户基本上没有什么感知。

而且对于业务调用方来说,只需要提供一个回调地址即可,然后在回调里面等着openid传过来就好,剩下的交给中控自己去来回蹦哒吧。

结尾

需要注意的是,公众号的后台需要配置好以下信息。

  1. JS接口安全域名:就是前端的访问域名。
  2. 网页授权域名:中控API域名。
  3. ip白名单:中控的ip地址。

否则是没有权限鉴权的。

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

Javascript 相关文章推荐
JQuery扩展插件Validate 3通过参数设置错误信息
Sep 05 Javascript
jquery Mobile入门—多页面切换示例学习
Jan 08 Javascript
JavaScript 动态加载脚本和样式的方法
Apr 13 Javascript
简介AngularJS中使用factory和service的方法
Jun 17 Javascript
jquery实现鼠标滑过后动态图片提示效果实例
Aug 10 Javascript
js中字符串编码函数escape()、encodeURI()、encodeURIComponent()区别详解
Apr 01 Javascript
使用do...while的方法输入一个月中所有的周日(实例代码)
Jul 22 Javascript
javascript滚轮事件基础实例讲解(37)
Feb 14 Javascript
Vue如何实现组件的源码解析
Jun 08 Javascript
JS中使用media实现响应式布局
Aug 04 Javascript
webpack-url-loader 解决项目中图片打包路径问题
Feb 15 Javascript
webpack介绍使用配置教程详解webpack介绍和使用
Jun 25 Javascript
Vue指令之 v-cloak、v-text、v-html实例详解
Aug 08 #Javascript
javascript实现blob加密视频源地址的方法
Aug 08 #Javascript
使用ThinkJs搭建微信中控服务的实现方法
Aug 08 #Javascript
微信小程序云函数使用mysql数据库过程详解
Aug 07 #Javascript
js如何实现元素曝光上报
Aug 07 #Javascript
详解Element-UI中上传的文件前端处理
Aug 07 #Javascript
element-ui中Table表格省市区合并单元格的方法实现
Aug 07 #Javascript
You might like
深入了解php4(2)--重访过去
2006/10/09 PHP
Zend Framework页面缓存实例
2014/06/25 PHP
简单分析ucenter 会员同步登录通信原理
2014/08/25 PHP
Laravel程序架构设计思路之使用动作类
2018/06/07 PHP
Javascript之文件操作
2007/03/07 Javascript
JavaScript在IE和Firefox(火狐)的不兼容问题解决方法小结
2010/04/13 Javascript
为jQuery增加join方法的实现代码
2010/11/28 Javascript
jquery定时滑出可最小化的底部提示层特效代码
2013/10/02 Javascript
JavaScript学习笔记之DOM基础 2.4
2015/08/14 Javascript
Bootstrap的popover(弹出框)2秒后定时消失的实现代码
2017/02/27 Javascript
iscroll-probe实现下拉刷新和下拉加载效果
2017/06/28 Javascript
浅谈webpack打包过程中因为图片的路径导致的问题
2018/02/21 Javascript
在Vue中获取组件声明时的name属性方法
2018/09/12 Javascript
详解ES6 Fetch API HTTP请求实用指南
2018/11/14 Javascript
es6中let和const的使用方法详解
2020/02/24 Javascript
JS+CSS实现3D切割轮播图
2020/03/21 Javascript
javascript局部自定义鼠标右键菜单
2020/12/08 Javascript
javascript实现简单留言板案例
2021/02/09 Javascript
[36:29]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 LGD vs TNC
2018/04/02 DOTA
python: line=f.readlines()消除line中\n的方法
2018/03/19 Python
python3 pandas 读取MySQL数据和插入的实例
2018/04/20 Python
详解python异步编程之asyncio(百万并发)
2018/07/07 Python
python3通过selenium爬虫获取到dj商品的实例代码
2019/04/25 Python
Python 3 判断2个字典相同
2019/08/06 Python
Python全栈之列表数据类型详解
2019/10/01 Python
python基于gevent实现并发下载器代码实例
2019/11/01 Python
Python基础进阶之海量表情包多线程爬虫功能的实现
2020/12/17 Python
CSS3实战第一波 让我们尽情的圆角吧
2010/08/27 HTML / CSS
amazeui模态框弹出后立马消失并刷新页面
2020/08/19 HTML / CSS
德国大型箱包和皮具商店:Koffer
2019/10/01 全球购物
Vita Fede官网:在意大利手工制作,在纽约市设计
2019/10/25 全球购物
事业单位分类改革实施方案
2014/03/21 职场文书
英语自我介绍演讲稿
2014/09/01 职场文书
房屋租赁合同补充协议
2014/10/11 职场文书
全陪导游词
2015/02/04 职场文书
CSS3 制作精美的定价表
2021/04/06 HTML / CSS