002-JS-SDK开发使用,网页获取授权,扫一扫调用
一、概述
在申请响应的公众号之后,实名认证或者企业认证之后,可以进行对应开发
二、开发步骤
2.1、开发前提【服务号】-域名设置
登录后台之后→左侧设置→公众号设置→功能设置,设置好“JS接口安全域名","网页授权域名"对应域名
2.2、开发前提【服务号】-开发者ID设置
登录后台之后→左侧开发→基本配置→公众号开发信息,设置好“开发者密码(AppSecret)”
2.3、查看接口信息
登录后台之后→左侧开发→接口权限→查看已开通的接口授权
三、调用示例
JS-SDK
接口列表:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 附录2
详情页:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
3.1、示例一、微信网页授权【地址】
1 第一步:用户同意授权,获取code
2 第二步:通过code换取网页授权access_token
3 第三步:刷新access_token(如果需要)
4 第四步:拉取用户信息(需scope为 snsapi_userinfo)
5 附:检验授权凭证(access_token)是否有效
1》整体流图
2》详细参看地值
微信网页授权【地址】
3.2、示例二、微信JS-SDK说明文档【地址 或者地址2】
JSSDK使用步骤【原文地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115】
步骤一:绑定域名
先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
备注:登录后可在“开发者中心”查看对应的接口权限。
步骤二:引入JS文件
在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js
备注:支持使用 AMD/CMD 标准模块加载方法加载
步骤三:通过config接口注入权限验证配置
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
步骤四:通过ready接口处理成功验证
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。
//对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
步骤五:通过error接口处理失败验证
wx.error(function(res){
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
接口调用说明
所有接口通过wx对象(也可使用jWeixin对象)来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:
1.success:接口调用成功时执行的回调函数。
2.fail:接口调用失败时执行的回调函数。
3.complete:接口调用完成时执行的回调函数,无论成功或失败都会执行。
4.cancel:用户点击取消时的回调函数,仅部分有用户取消操作的api才会用到。
5.trigger: 监听Menu中的按钮点击时触发的方法,该方法仅支持Menu中的相关接口。
备注:不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回。
以上几个函数都带有一个参数,类型为对象,其中除了每个接口本身返回的数据之外,还有一个通用属性errMsg,其值格式如下:
调用成功时:"xxx:ok" ,其中xxx为调用的接口名
用户取消时:"xxx:cancel",其中xxx为调用的接口名
调用失败时:其值为具体错误信息
3.3、示例三、根据2.5.5 以扫一扫为例:
1》服务器端设置js域名
2》html页面引用相关js
<script src="jquery.min.js" type="text/javascript"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
3》界面调用
<input type="button" value="扫一扫" id="btnScanCode" style="width: 80px"/>
4》相关JS代码
jQuery(document).ready(function () {
var getWechatSignUrl = "http://test.com/openapi/wechat/getJsApiSign'; // 获取微信签名
$.ajax({
url: getWechatSignUrl + "?url=" + encodeURIComponent(window.location.href.split('#')[0]),
success: function (o) {
console.log(o);
if (o.code == 20000) {
wxConfig(o.data.appId, o.data.timestamp, o.data.nonceStr, o.data.signature);
}
}, error: function (o) {
alert("出错了" + JSON.stringify(o));
}
});
function wxConfig(_appId, _timestamp, _nonceStr, _signature) {
var mm = '获取数据:' + encodeURIComponent(window.location.href.split('#')[0])
+ '\n' + _appId + '\n' + _timestamp + '\n' + _nonceStr + '\n' + _signature;
console.log(mm);
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: _appId, // 必填,公众号的唯一标识
timestamp: _timestamp, // 必填,生成签名的时间戳
nonceStr: _nonceStr, // 必填,生成签名的随机串
signature: _signature,// 必填,签名
jsApiList: ["scanQRCode"] // 必填,需要使用的JS接口列表
});
} function scanCode() {
wx.scanQRCode({
needResult: 1,
scanType: ["qrCode", "barCode"],
success: function (res) {
var result = res.resultStr;
alert(result);
},
fail: function (res) {
console.log(res)
alert(JSON.stringify(res));
}
});
} //客户端扫码
$("#btnScanCode").click(function () {
scanCode();
});
});
5》服务器端接口设计
全局响应枚举类
public enum ResponseEnum {
//账户类异常10000
USEREXCEPTION(10000, "账户异常"), SUCCESS(20000, "操作成功"),
//参数类异常 30000
NOTFOUND(30000, "必输参数为空"),
INPUTERROR(30001, "输入参数格式错误"),
DATEERROR(30002, "日期区间错误"),
DATEOUTOF(30003, "日期区间超出范围"), //系统类未知异常 99999
ERROR(99999, "系统异常"),; private int code;
private String msg; ResponseEnum(int code, String msg) {
this.code = code;
this.msg = msg;
} public int getCode() {
return code;
} public void setCode(int code) {
this.code = code;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} @Override
public String toString() {
return String.format("[%s:%s]", code, msg);
}
}
全局响应类
public class ResponseResult<T> { /**
* 方法返回状态码
*/
private int code; /**
* 方法返回信息
*/
private String msg; private T data; public ResponseResult(){
setResponseEnum(ResponseEnum.SUCCESS);} public ResponseResult(ResponseEnum enums){
setResponseEnum(enums);
} public ResponseResult(ResponseEnum enums, T data){
setResponseEnum(ResponseEnum.SUCCESS);
this.data = data;
} public ResponseResult(T data){
this(ResponseEnum.SUCCESS,data);
} public void setResponseEnum(ResponseEnum enums){
this.code = enums.getCode();
this.msg = enums.getMsg();
} public int getCode() {
return code;
} public String getMsg() {
return msg;
} public T getData() {
return data;
} public void setData(T data) {
this.data = data;
}
}
jsapi结果类
public class JsApiPageDomain {
private String appId; // 必填,公众号的唯一标识
private long timestamp; // 必填,生成签名的时间戳
private String nonceStr; // 必填,生成签名的随机串
private String signature;// 必填,签名
private String[] jsApiList;// 必填,需要使用的JS接口列表 public String getAppId() {
return appId;
} public void setAppId(String appId) {
this.appId = appId;
} public long getTimestamp() {
return timestamp;
} public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
} public String getNonceStr() {
return nonceStr;
} public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
} public String getSignature() {
return signature;
} public void setSignature(String signature) {
this.signature = signature;
} public String[] getJsApiList() {
return jsApiList;
} public void setJsApiList(String[] jsApiList) {
this.jsApiList = jsApiList;
}
}
获取getJsApiSign
@RequestMapping(value = "/getJsApiSign", method = RequestMethod.GET)
@ResponseBody
public ResponseResult<JsApiPageDomain> getJsApiSign(String url) {
ResponseResult<JsApiPageDomain> result = new ResponseResult<>();
JsApiPageDomain jsApiPageDomain = null;
try {
//返回页面签名等信息
//时间戳
long timeStamp = System.currentTimeMillis()/1000L;
//字母数字随机串
String nonceStr = RandomStringUtils.randomAlphanumeric(16);
//获取JsApITicket
String jsApiTicket = weChatUtil.getJsApiTicket();
jsApiPageDomain = new JsApiPageDomain();
jsApiPageDomain.setAppId(globalConfig.getWeChatAppID());
jsApiPageDomain.setNonceStr(nonceStr);
jsApiPageDomain.setTimestamp(timeStamp);
jsApiPageDomain.setSignature(weChatUtil.signature(nonceStr, jsApiTicket, timeStamp, url));
jsApiPageDomain.setJsApiList(new String[]{"scanQRCode"});
result.setData(jsApiPageDomain);
} catch (Exception e) {
logger.error("getJsApiSign请求异常", e);
}
return result;
}
获取基础access_token【参看地址】
/**
* 获取access_token
*
* @return
*/
public String getAccessToken() {
//redis读取
if (RedisUtil.exist(interfaceAccessTokenKey)) {
String redis = RedisUtil.findValueFromRedis(interfaceAccessTokenKey);
if (StringUtils.isNotBlank(redis)) {
return redis;
}
}
//执行调用
ResponseEntity<InterfaceAccessToken> entity = restTemplate.getForEntity(globalConfig.getWechatInterfaceAccessToken(), InterfaceAccessToken.class);
if (entity != null && entity.getStatusCode() == HttpStatus.OK) {
if (entity.getBody() != null&&StringUtils.isNotBlank(entity.getBody().getAccess_token())) {
RedisUtil.saveToRedis(interfaceAccessTokenKey, entity.getBody().getAccess_token());
int tmp = entity.getBody().getExpires_in() - (60 * 5);
RedisUtil.setExpire(interfaceAccessTokenKey, tmp>0?tmp:1, TimeUnit.SECONDS);
return entity.getBody().getAccess_token();
}
}
return null;
}
获取jsapi_ticket【参看地址 附录1】
/**
* 获取jsapi_ticket
*
* @return
*/
public String getJsApiTicket() {
String token = getAccessToken();
if (StringUtils.isBlank(getAccessToken())) {
return null;
} //redis读取
if (RedisUtil.exist(jsapiTicketKey)) {
String redis = RedisUtil.findValueFromRedis(jsapiTicketKey);
if (StringUtils.isNotBlank(redis)) {
return redis;
}
} String apiTicket = MessageFormat.format(globalConfig.getWechatJsApiTicket(), token);
//执行调用
ResponseEntity<JsApiTicket> entity = restTemplate.getForEntity(apiTicket, JsApiTicket.class);
if (entity.getStatusCode() == HttpStatus.OK) {
if (entity.getBody() != null&&StringUtils.isNotBlank(entity.getBody().getTicket())) {
RedisUtil.saveToRedis(jsapiTicketKey, entity.getBody().getTicket());
//过期时间
Long ttl = RedisUtil.ttl(interfaceAccessTokenKey);
if (ttl != null && (ttl.longValue() - 1 > 0)) {
RedisUtil.setExpire(jsapiTicketKey, ttl.longValue() - 1, TimeUnit.SECONDS);
} else {
getJsApiTicket();
}
return entity.getBody().getTicket();
}
}
return null;
}
注意 基础access_token 和 jsapi_ticket 使用为redis缓存,同时具有相同的失效时间
签名
public String signature(String noncestr, String jsapiTicket, long timestamp, String url) {
TreeMap<String, String> map = new TreeMap<>();//以后扩展方便
map.put("noncestr", noncestr);
map.put("jsapi_ticket", jsapiTicket);
map.put("timestamp", String.valueOf(timestamp));
map.put("url", url); StringBuilder sb = new StringBuilder();
map.forEach((k, v) -> {
sb.append(k + "=" + v + "&");
});
String msg = sb.toString().substring(0, sb.length() - 1);
System.out.println("加密信息:" + msg);
//签名
MessageDigest m = null;
try {
m = MessageDigest.getInstance("SHA-1");
m.update(msg.getBytes("UTF8"));
} catch (Exception e) {
e.printStackTrace();
return null;
}
byte s[] = m.digest();
return Hex.encodeHexString(s);
}
002-JS-SDK开发使用,网页获取授权,扫一扫调用的更多相关文章
- 实战微信JS SDK开发:贺卡制作与播放(1)
前段时间忙于CanTK 2.0的开发,所以博客一直没有更新.CanTK 2.0主要增强了游戏和富媒体的开发,现在编码和测试基本完成了,等文档完成了再正式发布,里面有不少激动人心的功能,等发布时再一一细 ...
- js 微信公众号网页用户授权,获取微信code,access_tocken,用户信息
第一次做微信网页授权,过程有点艰难,主要是不知道redirect_uri的地址要怎么写,刚开始我以为就是授权结束后要跳转到的首页地址,于是写成了uri = 'http://18i194c049.ias ...
- 实战微信JS SDK开发:贺卡制作与播放(2)
最近同事用CanTK开发了一个基于微信的贺卡制作APP,我虽然没有参与开发,但是提供CanTK和GameBuilder的技术支持,觉得有些东西比较有意思,写几篇博客和大家分享吧.这个贺卡APP完全开源 ...
- 公众号第三方平台开发 教程六 代公众号使用JS SDK说明
公众号第三方平台开发 教程一 创建公众号第三方平台 公众号第三方平台开发 教程二 component_verify_ticket和accessToken的获取 公众号第三方平台开发 教程三 微信公众号 ...
- 微信JS SDK配置授权,实现分享接口
微信开放的JS-SDK面向网页开发者提供了基于微信内的网页开发工具包,最直接的好处就是我们可以使用微信分享.扫一扫.卡券.支付等微信特有的能力.7月份的时候,因为这个分享的证书获取问题深深的栽了一坑, ...
- Node.js SDK与fabric链码交互开发
1.本篇背景 前面已经对链码开发作了比较详细的介绍,并且对官方提供的 fabcar 链码进行了解读,本篇将介绍如何使用 Node.js SDK 与区块链网络中的链码进行交互. 本篇内容基本来自官方 H ...
- node.js 微信开发2-消息回复、token获取、自定义菜单
项目结构 >config/wechat.json 微信公众号的配置文件 >controllers/oauth.js 微信网页授权接口(下一篇再细讲讲) >controllers/we ...
- PHP实现微信网页登陆授权开发
这篇文章主要介绍了关于PHP实现微信网页登陆授权开发,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 更多PHP相关知识请关注我的专栏PHPzhuanlan.zhihu.com 微信开 ...
- 微信开发中网页授权access_token与基础支持的access_token异同
问题1:网页授权access_token与分享的jssdk中的access_token一样吗? 答:不一样.网页授权access_token 是一次性的,而基础支持的access_token的是有时间 ...
随机推荐
- DB2创建库 数据恢复
例:数据库:PRODB2用户 :DB2ADMIN/DB2ADMIN备份库路径:D:/bank 一.恢复数据库1.启动数据库运行->db2cmd->db2Db2=>start db m ...
- Maven-Eclipse使用maven创建HelloWorld Java项目,使用Junit-4.11的注解
1.针对前面创建的mavenTest项目,我们做一些修改,包括pom.xml.App.java.AppTest.java 说明:其中的scope属性,如果是test,表示该依赖只对测试有效,如果不声明 ...
- RPC-基于原生java实现
一:什么是RPC 远程过程调用(Remote Procedure Call).就是调用其他业务方的方法的时候,就像是调用自己本地的方法一样. 二:java rpc实现简介 服务端(使用反射) (1)服 ...
- [2019杭电多校第三场][hdu6608]Fansblog
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6608 大致题意是比p小的最大素数q,求q!%p的值. 由威尔逊定理开始推: $(p-1)!\equiv ...
- Django中orm的惰性机制
那么首先要知道什么是ORM 专业化的角度来说:叫对象关系映射(Object-Relation Mapping)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 那具体ORM是什么呢?:( ...
- 生日蛋糕 (poj1190) (dfs剪枝)
[题目描述] 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为 ...
- Feign负载均衡
Feign是一个声明式的Web Service客户端,比Ribbon好用,默认也是轮巡.我们只需要使用Feign创建一个接口,并用注解就好了.如果你基于spring cloud发布一个接口,实际上就是 ...
- 08-js流程控制、循环、元素操作
# js流程控制 > 流程控制用于基于不同的条件来执行不同的动作. ### if语句 >if... else ... >if ... else if ... else... > ...
- more - 在显示器上阅读文件的过滤器
总览 (SYNOPSIS) more [-dlfpcsu ] [-num ] [+/ pattern] [+ linenum] [file ... ] 描述 (DESCRIPTION) More 是 ...
- 基于双TMS320C6678+双XC6VSX315T的6U VPX高速数据处理平台
基于双TMS320C6678+双XC6VSX315T的6U VPX高速数据处理平台 一.板卡概述 板卡由我公司自主研发,基于VPX架构,主体芯片为两片 TI DSP TMS320C6678,两片V ...