最近公司搞了个运营活动,入口放在了微信公众号里,好久没碰过微信了,刚拾起来瞬间感觉有点懵逼。。。。似乎把之前的坑又都重新踩了一遍,虽然过程曲折,不过好在顺利完成了,而且印象也更加深刻了,抽时间记录一下过程,不然下次再被绊倒的话,就要被老铁们笑话啦。好了,废话不多说,进入正题(先捋一捋流程,再说要注意的问题):

1.公众号配置相关:

  登录微信开放平台,找到对应公众号,设置业务域名,JS接口安全域名,网页授权域名等乱七八糟的一堆(文档或者网上都有,可对比参考一下,这里就不赘述了)。

2.接入JSSDK:

  页面头部引入即可:

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

3.获取access_token、ticket及signature:

//appid、秘钥、随机字符串(不要试图用这些做坏事,因为机智的我已经预料到了。。。)
const APPID = 'wxdc8b4f8e3esdfsdfasd';
const SECRET = 'f5a5fa443923e3fdsfasdasf0';
const NONCESTR = 'Wm3WZYTPz0fdsfasdf';
let timestamp = (new Date()).getTime();
let access_token = '';
let jsapi_ticket = ''; //获取access_token
function getToken(callback) {
const newsUrl= 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + APPID + '&secret=' + SECRET;
request(newsUrl, function (error, response, body) {
if(error || response.statusCode != '200'){
getToken(callback);
return;
} let obj;
try{
obj = JSON.parse(body);
}catch(e){
console.log(e);
}
if(!obj || !('access_token' in obj)){
console.log('Get access token error!', error, response.statusCode, body);
getToken(callback);
return;
} access_token = JSON.parse(body).access_token;
console.log('Got new access token:', access_token);
timestamp = (new Date()).getTime();
getTicket(callback);
});
}
function getTicket(callback) {
const newsUrl= 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi';
request(newsUrl, function (error, response, body) {
if (!error && response.statusCode == '200') {
if (JSON.parse(body).errcode === 0) {
jsapi_ticket = JSON.parse(body).ticket;
if(callback) {
callback();
}
}
} else {
response.status(response.statusCode).send(body);
}
});
} //签名加密
function getSignature(url) {
const str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + NONCESTR + '&timestamp=' + timestamp + '&url=' + url;
const sha1 = crypto.createHash('sha1');
return sha1.update(str).digest('hex');
}

4.通过接口将appId、timestamp、noncestr、signature返回值页面:

router.get('/wxconfig', function(req, res) {
let date = (new Date()).getTime();
  //access_token有效时间为2小时
if(date - timestamp >= 7200 * 1000) {
getToken(function () {
let signature = getSignature(req.query.url); res.send({
appId: APPID,
timestamp: timestamp,
nonceStr: NONCESTR,
signature: signature
});
});
}
else {
     //这里的url是调用接口时传来的,必须是动态获取当前页面地址‘#’号之前的部分
let signature = getSignature(req.query.url);
res.send({
appId: APPID,
timestamp: timestamp,
nonceStr: NONCESTR,
signature: signature
});
}
});

5.调用'/wxconfig'接口,配置自定义分享信息:

getSignature() {
  let url = window.location.href.split('#')[0];
this.$http.get('/lucky-draw/wxconfig', { params: { url: url } }).then(data => {
this.wxConfig(data.body);
this.wxReady();
}, error => {
console.log(error);
});
}
wxConfig(options) {
wx.config({
debug: false,
appId: options.appId,
timestamp: options.timestamp,
nonceStr: options.nonceStr,
signature: options.signature,
openid: '',
jsApiList: [
'onMenuShareTimeline',
'onMenuShareAppMessage'
]
});
}

wxReady() {
let _this = this;
let id = _this.getQueryString('acti');
let options = {
title: 'xxxxxxxxxxx',
desc: 'xxxxxxxxxxx',
link: 'xxxxxxxxx',
imgUrl: 'xxxxxxxxxx',
success: function (data) {
_this.addOneChanceAfterShare();
},
cancel: function (data) {
console.log(data);
}
};
wx.ready(function () {
wx.onMenuShareTimeline(options);
wx.onMenuShareAppMessage(options);
});
}

6.获取微信授权:

  因为授权登录的权限较高,所以微信平台会对链接的顺序进行校验,顺序是固定的。链接格式如下:

“https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect”

  解释一下参数:

  appid:公众号的appid;

  redirect_uri:微信授权成功之后需要跳转的链接(你希望授权成功之后跳转到哪个页面,这里就填哪个);

  response_type:固定参数“code”(告诉微信给你返回code,这个解释是不是简单粗暴了些);

  scope:授权权限,主要分两种,“snsapi_base”:静默授权,用户无感知,但是只能获取到openid;“snsapi_userinfo ”:弹出询问框,需要用户手动确认,可以拿到openid及用户基本信息;

  state:没搞太明白是干什么用的,但有一点可以确定,你传什么参数,微信授权跳转之后还会给你带回去这个参数,特定场合可能会用到;

  wechat_redirect:这个可以去掉,没有影响。

7.拿code换取openid:

  因为我这次做的是一个活动的单页面,页面上需要根据用户的openid及unionid从后台获取数据,所以我希望在进入页面之前就已经拿到我需要的东西了(openid和unionid以及一些数据),我的做法是把回调地址写在node里,以接口的形式接受微信的跳转(这里用词是不是太生硬了啊,哈哈,自行理解一下吧):

  

//获取code时微信回调地址
router.get('/is_wx_redirect', function (req, res) {
//拿code
let code = req.query.code || '';
console.log('Get code success!!!', code); //拿活动id
let id = req.query.acti;
req.session.acti_id = id; let openid, unionid, subscribe; getOpenId(); //获取openid
function getOpenId () {
let url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' + APPID + '&secret=' + SECRET + '&code=' + code + '&grant_type=authorization_code';
request(url, function (error, response, body) {
if (error || response.statusCode != '200') {
console.log('获取openid时发生错误:', error);
res.send('获取openid时发生错误,错误信息为:' + error);
return false;
}
let data = JSON.parse(body);
if (!data.openid) {
console.log('发送请求openid成功,但是返回信息中没有openid');
res.send(body);
}
//获取openid成功后,获取unionid和是否关注等信息
openid = data.openid;
console.log('我拿到openid了,openid是:', openid);
getIsFocus();
});
}
//获取unionid和是否关注等信息
function getIsFocus () {
let url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' + access_token + '&openid=' + openid + '&lang=zh_CN';
request(url, function (error, response, body) {
if (error || response.statusCode != '200') {
console.log('获取unionid时发生错误:', error);
res.send('获取unionid时发生错误,错误信息为:' + error);
return false;
}
let data = JSON.parse(body);
subscribe = data.subscribe || '';
unionid = data.unionid || ''; //存session
req.session.openid = openid;
req.session.unionid = unionid;
req.session.subscribe = subscribe; console.log('我拿到unionid了,unionid是:', unionid);
console.log('我拿到subscribe了,subscribe是:', subscribe); if (!subscribe) {
//未关注
console.log('The user is not focus!!');
res.redirect('/lucky-draw/focus_page', 302);
return false;
} if (!unionid) {
//返回信息中无unionid
res.send('返回信息中未包含unionid' + data);
return false;
} //重定向至主页面
console.log('Start redirect!!!!');
res.redirect('/lucky-draw/?acti=' + id, 302);
console.log('Redirect success!!');
});
}
});

  眼尖的老铁可能一眼就发现了几个问题:

  1)我并没有用拿到的code去换access_token,而是用之前自定分享时获取过的全局token,这里需要注意了,全局access_token和网页授权access_token是有区别的,获取地址、参数、时效及用途都不同,千万可别弄混淆了,不然非得坑死你(别胡说,我才没被这个坑过。。。。),关于这两个access_toekn的具体区别及用途,可以自行查一下。因为我只需要判断用户是否关注了公众号,从而完成一项业务需求,并不需要用户的基本信息,所以我只拿code换取了openid,然后用openid和全局access_token获取unionid;

  2)大堆的log有木有!!微信开发的调试相对来说还是比较简(恶)单(心)的,关键位置的log获取错误处理,会让我们少走很多弯路。

8.其实代码已经写在上一步了,就是拿到初始化页面所需要的信息之后,重定向至该页面。

NodeJs实现自定义分享功能,获取微信授权+用户信息的更多相关文章

  1. ThinkPHP5集成JS-SDK实现微信自定义分享功能

    最近开发一个项目,需要将链接分享给好友时能够自定义标题.简介和logo,现将ThinkPHP5集成JS-SDK实现微信自定义分享功能的过程整理成文. 一.准备工作 1.认证的公众号 不管是订阅号还是服 ...

  2. c#微信开发,使用JS-SDK自定义分享功能,分享朋友圈,分享给朋友等

    如果一个后端开发掌握了微信开发,甚至有微信开发上线项目,这在换工作的时候 还是有竞争力的. 微信开发的资料很多,但是用asp.net c#进行微信开发好像比较少,或者资料不够完整. 使用JS-SDK自 ...

  3. Chrome获取微信授权,调试公众号页面

    1.目的 你可能遇到过这种情况,在微信中打开公众号是这样的. 复制链接,在chrome中打开是这样的. 博主今天要解决的就是,如果在chrome中加载需要微信授权的页面,至于加载成功后要干嘛,测试?抓 ...

  4. 微信公众号基础02_获取accessToken和用户信息

    上一篇分享了搭建微信公众号server,本文分享一下假设获取access_Token和用户信息.工具还是新浪云SAE 1.获取access_Token 相见开发文档:https://mp.weixin ...

  5. 微信公众号开发之如何一键导出微信所有用户信息到Excel

    微信开发交流群:148540125 系列文章参考地址 极速开发微信公众号欢迎留言.转发.打赏 项目源码参考地址 点我点我--欢迎Start 极速开发微信公众号系列文章之如何一键导出微信所有用户信息到E ...

  6. spring oauth2获取当前登录用户信息。

    使用spring oauth2框架做授权鉴定.想获取当前用户信息怎么办? 我们知道spring oauth2是基于spring security的实现的. spring security可以通过Sec ...

  7. 黄聪:WordPress 多站点建站教程(五):获取子站点用户信息(通过输入站点ID号来获取该站点的所有用户)

    得到站点ID为1的用户 <ul> <?php $blogusers = get_users('blog_id=1'); foreach ($blogusers as $user) { ...

  8. C# 微信openid 用户信息

    前段demo index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...

  9. 使用微信JS-SDK 实现 自定义 分享 功能

    微信PC端点击页面,转发给朋友.

随机推荐

  1. C# Redis实战(六)

    六.查询数据 在C# Redis实战(五)中介绍了如何删除Redis中数据,本篇将继续介绍Redis中查询的写法. 1.使用Linq匹配关键字查询 using (var redisClient = R ...

  2. Windows下安装TensorFlow

    最近学习TensorFlow,当然前提是装好框架,网上教程很多都是虚拟搭建或者是conda,从我的经验来讲,Windows目前只支持Python3.5版本安装,Python官网上有说明: 本人由于常用 ...

  3. git记录(给老婆找的地址)

    ssh配置 https://blog.igevin.info/posts/generate-ssh-key-for-git/ git 查看某个文件的修改历史 1. git log -p filenam ...

  4. Win32 API之绘图函数

    AbortPath 抛弃选入指定设备场景中的所有路径.也取消目前正在进行的任何路径的创建工作 AngleArc 用一个连接弧画一条线 Arc 画一个圆弧 BeginPath 启动一个路径分支 Canc ...

  5. C++通过ADO读写Excel文件

    介绍 有时候我们需要从excel表格里导入.导出数据.其中一种方式就是通过ADO的方式.在这里,excel文件被当作数据库来处理,该方式不需要客户端安装Microsoft Excel,速度也够快. 连 ...

  6. python基础学习二 数据结构之list及相关基本操作

    list是py内置的一种数据类型,list就是列表的意思,list就是一种有序的数据集合,可以随时增加和删除list的元素. 生活中,比如我们要列出全班同学的名字,就可以用list来表示 >&g ...

  7. LeetCode --> 771. Jewels and Stones

    Jewels and Stones You're given strings J representing the types of stones that are jewels, and S rep ...

  8. #Python3.6.2(32位) pip安装 和 pygame 环境配置

    #首先确认电脑已经安装python ,可通过在命令行下 执行 python --version确认. 1. 到 https://pypi.python.org/pypi/setuptools/ 下载 ...

  9. Android一个小巧的记录app(便签或者日记 随心)

    入驻博客园两个月今天第一次发随笔,,话不多说,直接上图展示效果 主界面用的RecyclerView的瀑布流(StaggeredGridLayoutManager),同时加上Floatbutton悬浮按 ...

  10. postman简单教程,使用tests模块来验证接口时是否通过

    接口测试醉重要的就是返回数据的检查,一个简单的接口,我们可以肉眼检查返回数据,但接口一旦多起来且复杂,每次的检查都会很费劲,此时我们就需要postman 的tests模块来代替 概念: Postman ...