微信JS-SDK说明文档
//拍照页面
@RequestMapping("/getTakePhotos")
public ModelAndView getTakePhotos(HttpServletRequest request) {
logger.info(">>>>>>>>>>>>>>>>获取拍照页面>>>>>>>>>>>>>>>>");
ModelAndView modelAndView = new ModelAndView();
// 部署服务器开启
String code = request.getParameter("code");
logger.info("code为:{}", code);
if (StringUtils.isBlank(code)) {
logger.info("进来这人没code,有问题");
modelAndView.addObject("openId", "");
modelAndView.addObject("errorInfo", "openId为空");
modelAndView.setViewName("/mobile/404");
return modelAndView;
}
String openid = "";
try {
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + ParamesAPI.appId+ "&secret=" + ParamesAPI.secret + "&code=" + code + "&grant_type=authorization_code";
logger.info("url:{}", url);
JSONObject result = HttpsClient.httpRequest(url, "GET", null);
logger.info("获取openId的json:{}", result);
openid = (String) result.get("openid");
if (StringUtils.isEmpty(openid)) {
logger.info("openid为空:{}", openid);
/**
* 跳转错误页面
*/
modelAndView.setViewName("/mobile/404");
return modelAndView;
}
request.getSession().setAttribute("openId", openid);
} catch (Exception e) {
logger.info("未知错误:{}", e);
modelAndView.addObject("openId", "");
modelAndView.addObject("errorInfo", "openId为空");
modelAndView.setViewName("/mobile/404");
return modelAndView;
}
modelAndView.setViewName("mobile/takePhotos");
return modelAndView;
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
<html>
<head>
<meta charset="utf-8">
<title>微信拍照title>
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<script type="text/javascript" src="resources /lib/jquery/jquery-1.11.0.min.js" />">script>
<link href="resources /mui/css/mui.min.css" />" rel="stylesheet">
<link href="resources /mui/css/app.css" />" rel="stylesheet">
head>
<body>
<div>
<header class="mui-bar mui-bar-nav">
<a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left">a>
<h1 class="mui-title">微信拍照h1>
header>
<div class="mui-content">
<a href="javascript:;" onclick="take_a_photo()">调用微信相机a><br>
div>
<br/><br/><br/><br/>
<div>
appId:<span id="appId">span><br/><br/>
timestamp:<span id="timestamp">span><br/><br/>
nonceStr:<span id="nonceStr">span><br/><br/>
jsapi_ticket:<span id="jsapi_ticket">span><br/><br/>
signature:<span id="signature">span><br/><br/>
originalStr:<span id="originalStr">span><br/><br/>
scan_result:<span id="result">span><br/><br/>
div>
div>
body>
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js" type="text/javascript">script>//步骤二:引入JS文件
<script type="text/javascript">
$(function(){
get_wx_config();
})
function get_wx_config(){
//url(当前网页的URL,不包含#及其后面部分)
var url = window.location.href.split('#')[0];
var indata = {"url":url};
$.post("" />" , indata, function(data){
if(data.rs == 'f'){
alert("系统错误");
}else{
var result = data;
$("#appId").text(result.appId);
$("#timestamp").text(result.timestamp);
$("#nonceStr").text(result.nonceStr);
$("#jsapi_ticket").text(result.jsapi_ticket);
$("#signature").text(result.signature);
$("#originalStr").text(result.originalStr);
//步骤三:通过config接口注入权限验证配置
wx.config({
debug: true,
appId: result.appId, // 必填,公众号的唯一标识
timestamp: result.timestamp, // 必填,生成签名的时间戳
nonceStr: result.nonceStr, // 必填,生成签名的随机串
signature: result.signature,// 必填,签名,见附录1
jsApiList: ["chooseImage", "previewImage", "uploadImage", "downloadImage"] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
// 基本思路是,上传图片到微信服务器->下载多媒体接口将图片下载到服务器->返回服务器存储路径->前台显示
});
// 步骤四:通过ready接口处理成功验证
wx.ready(function(){
alert("wx.config success.");
});
wx.error(function(res){
alert("wx.config failed.");
//alert(res);
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,
// 也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
// {"errMsg":"config:invalid signature"}
}
},'json');
}
// 图片接口
// 拍照、本地选图
var images = {
localId: [],
serverId: []
};
// 拍照或者选择照片
function take_a_photo(){
wx.chooseImage({
count: 1, // 默认9,这里每次只处理一张照片
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
images.localId = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
var i = 0, length = images.localId.length;
function upload() {
wx.uploadImage({
localId: images.localId[i],// 需要上传的图片的本地ID,由chooseImage接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: function(res) {
i++;
alert('已上传:' + i + '/' + length);
images.serverId.push(res.serverId);// 返回图片的服务器端ID
// res.serverId 就是 media_id,根据它去微信服务器读取图片数据:
var indata = {"media_id":res.serverId};
$.post("/wechat/admin/orderBase/getPhoto.json", indata, function(data){
if(data.rs == 'f'){
alert("系统错误");
}else{
alert(data); // 返回 图片在我们自己的服务器的url
wx.downloadImage({
serverId: '', // 需要下载的图片的服务器端ID,由uploadImage接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: function (res) {
var localId = res.localId; // 返回图片下载后的本地ID
}
});
}
},'json');
if (i < length) {
upload();
}
},
fail: function(res) {
alert(JSON.stringify(res));
}
});
}
upload();
}
});
}
script>
html>
-后台: 获取config接口注入权限接口
/**
* 获取config接口注入权限
*/
@RequestMapping("/getConfigInfo")
@ResponseBody
public JSONObject getConfigInfo(HttpServletRequest request,String url) {
JSONObject jsonObject=new JSONObject();
String noncestr = "Wm3WZYTPz0wzccnW";
AccessToken accessToken=WeixinUtil.getAccessToken(ParamesAPI.appId,ParamesAPI.secret);
String ticket= WeixinUtil.getJsapiTicket(accessToken.getToken(),request);
if(ticket!=null){
Date date=new Date();
Long timestamp=date.getTime();
StringBuilder sb = new StringBuilder("jsapi_ticket=");
sb.append(ticket).append("&noncestr=").append(noncestr)
.append("×tamp=").append(timestamp).append("&url=").append(url);
try {
//指定sha1算法,加密
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] bt = sb.toString().getBytes();
md.update(bt);
//获取字节数组
byte messageDigest[] = md.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
String signature=hexString.toString().toUpperCase();
/*String signature=bytes2Hex(md.digest());*/ //返回16进制字符串
jsonObject.put("jsapi_ticket",ticket);
jsonObject.put("appId",ParamesAPI.appId);
jsonObject.put("timestamp",timestamp);
jsonObject.put("nonceStr",noncestr);
jsonObject.put("signature",signature);
jsonObject.put("originalStr", sb.toString());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
/*MessageDigest md = MessageDigest.getInstance("SHA-1");
// 对接后的字符串进行sha1加密
byte[] digest = md.digest(sb.toString().getBytes());
String signature = SignUtil.byteToStr(digest).toLowerCase();*/
}
return jsonObject;
}
JS-SDK使用权限签名算法:
jsapi_ticket
jsapi_ticket是公众号用于调用微信JS接口的临时票据,正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。
1. 获取access_token:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
2. 用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
成功返回如下JSON:
{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}
获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。
签名算法
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
即signature=sha1(string1)。 示例:
noncestr=Wm3WZYTPz0wzccnW
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
timestamp=1414587457
url=http://mp.weixin.qq.com?params=value
步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
步骤2. 对string1进行sha1签名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事项
1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
2.签名用的url必须是调用JS接口页面的完整URL。
3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
如出现invalid signature 等错误详见附录5常见错误及解决办法。
相关博客地址:
1.调用微信相机:http://www.cnblogs.com/digdeep/p/5743378.html
2.signature的生成:http://blog.csdn.net/november22/article/details/54916933
3.SHA1加密、以及转化为十六进制:http://blog.csdn.net/w501631338/article/details/54406680