2016-08-09 17:21:29 qq_31583959 阅读数 4325

以下是微信开发文档中获取jsapi_ticket 的说明 :

jsapi_ticket

生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。

1.参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):../15/54ce45d8d30b6bf6758f68d2e95bc627.html

2.用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存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 第一步要获取 access_token。

大家可以参考 我的上一篇文章:使用C# .net开发微信公众号之获取AccessToken 中的方法来获取 access_token

获取了access_token 我们就可以获取 jsapi_ticket 了。

根据说明,我们要通过get方式请求这个微信接口: 

https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

然后我们开始写代码:我先把自己写的代码贴出来,大家可以改造一下拿去用(这个也可以直接用的,但要理解里面的意思哦)

        /// <summary>
        /// 获取Jsapi_Ticket
        /// </summary>
        /// <returns></returns>
        public static Jsapi_Ticket GetWeiXinJsapi_Ticket(string accessToken)
        {
            string type = "jsapi";
            string tokenUrl = string.Format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type={1}", accessToken, type);
            var wc = new WebClient();
            var strReturn = wc.DownloadString(tokenUrl); //取得微信返回的json数据
            return strReturn<span style="line-height: 22.4px; font-family: arial, helvetica, sans-serif;">;</span>
        }


然后我们就取得了如下的数据:

{

"errcode":0,

"errmsg":"ok",

"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",

"expires_in":7200

}

如果返回别的json数据大家可以去微信公众平台查询相应的错误码  全局返回码说明

注:因为jsapi_ticket 有时间限制,过期就不能用了,所有大家最好要做好缓存处理。缓存方法就不给大家贴了。如果有需要我在开一篇做缓存处理的文章。

此方式或许有不妥之处,热烈欢迎大家吐槽。。。 错误之处也请大家指正,谢谢  -----    WeepingWeeper


谢谢大家观看参考,让我们一同进步。


微信的其他接口调用在持续更新中。。。欢迎关注持续关注。。

2017-11-16 11:48:46 qq_37936542 阅读数 6649

 

access_token:公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。

 

 

jsapi_ticket:jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。

 

 

由于上述两个标识获取都有限制,而且有效期是两个小时,所以开发时设置为每一小时获取一次

 

 

(一):导入httpclient依赖和jackson依赖

<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient-cache</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.1.2</version>
</dependency>


<!-- jack json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.3</version>
</dependency>

 

 

 

(二):封装httpclient处理get和post请求

import java.io.IOException;
import java.util.List;


import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;


import com.fasterxml.jackson.databind.ObjectMapper;
public class CommonUtils {

private static HttpClient CLIENT = new DefaultHttpClient();

private static ObjectMapper MAPPER = new ObjectMapper();

public static String APPID ="wx273a3bf59a7d2fee";

public static String SECRET="0ca672094780b3ecf9cedcf35891b129";

/**
* 根据url获取返回对象
* @param <T>
* @param url
* @return 
* @throws Exception
*/
public static <T> T returnMsg(String url,Class<T> clazz) throws Exception{
HttpPost msgPost = new HttpPost(url);
String str = EntityUtils.toString(CLIENT.execute(msgPost).getEntity(),"UTF-8");
return MAPPER.readValue(str, clazz);
}


/**
* httpclient模拟get请求
*/
public static String Get(String url) throws Exception{
HttpGet httpGet = new HttpGet(url);
String str = EntityUtils.toString(CLIENT.execute(httpGet).getEntity(),"UTF-8");
return str;
}

/**
* http模拟post请求,请求参数是json数据
* @param url
* @param param
* @return
* @throws IOException 
* @throws Exception 
*/
public static String Post_Json(String url, String param) throws Exception{
HttpPost httpPost = new HttpPost(url);
//防止参数乱码
        httpPost.addHeader("Content-type","application/json; charset=utf-8");  
        httpPost.setEntity(new StringEntity(param, "UTF-8"));
        //执行请求
        HttpResponse execute = CLIENT.execute(httpPost);
        String resp = EntityUtils.toString(execute.getEntity());
        return resp;

}

/**
* httpclient模拟表单提交
* @param url
* @param param
* @return
* @throws Exception
*/
public static String Post_From(String url, List<NameValuePair> list) throws Exception{
HttpPost httpPost = new HttpPost(url);
//防止参数乱码
        httpPost.addHeader("Content-type","application/json; charset=utf-8");  
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
        httpPost.setEntity(entity);
        //执行请求
        HttpResponse execute = CLIENT.execute(httpPost);
        String resp = EntityUtils.toString(execute.getEntity());
        return resp;
}


}

 

(三):获取access_token和jsapi_ticket

import org.springframework.stereotype.Service;


import com.mote.weixin.utils.CommonUtils;


/**
 * 定时刷新access_token--微信全局凭证
 * 定时刷新jsapi_ticket--调用微信js接口的临时票据
 * @author lenovo
 *
 */
@Service("tokenService")
public class TokenService {

private String access_token;
private String jsapi_ticket;

public String getAccess_token() {
return access_token;
}


public void setAccess_token(String access_token) {
this.access_token = access_token;
}


public String getJsapi_ticket() {
return jsapi_ticket;
}


public void setJsapi_ticket(String jsapi_ticket) {
this.jsapi_ticket = jsapi_ticket;
}


/**
* 将该方法配置成定时任务,程序启动后五秒自动调用,
* 之后每隔一小时刷新一次
*/
public void flush(){

System.out.println("===================我被调用了=================");

try {
//获取access_token
String accessToken = CommonUtils.getAccessToken();
this.access_token = accessToken;

//获取jsapi_ticket
String jsApiTicket = CommonUtils.getJsApiTicket(accessToken);
this.jsapi_ticket = jsApiTicket;


} catch (Exception e) {
System.out.println("刷新access_token失败");
e.printStackTrace();
}

}

}

 

 

 

(四):定义AccessToken对象,然后在CommonUtils中添加获取access_token和jsapi_ticket的方法

public class AccessToken {
	// 接口访问凭证
	private String accessToken;
	// 凭证有效期,单位:秒
	private int expiresIn;

	public String getAccessToken() {
		return accessToken;
	}

	public void setAccessToken(String accessToken) {
		this.accessToken = accessToken;
	}

	public int getExpiresIn() {
		return expiresIn;
	}

	public void setExpiresIn(int expiresIn) {
		this.expiresIn = expiresIn;
	}
}

 

/**
* 获取access_token
* @return
* @throws Exception
*/
public static String getAccessToken() throws Exception{
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APPID+"&secret="+SECRET+"";
AccessToken token = returnMsg(url, AccessToken.class);
return token.getAccessToken();
}

/**
     * 获取调用微信JS接口的临时票据
     * 
     * @param access_token 微信全局凭证
     * @return
* @throws IOException 
* @throws Exception 
     */
    public static String getJsApiTicket(String access_token) throws Exception{
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+access_token+"&type=jsapi";
        // 发起GET请求获取凭证
        String resq = Get(url);
        JsonNode tree = MAPPER.readTree(resq);
        return tree.get("ticket").toString().replaceAll("\"", "");
    }

 

 

 

 

(五):配置TokenService中的flush方法,使其生效

注意:引入xml约束

xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">

 

 

 

配置如下:

<!-- 如果TokeService添加了注解,bean可以省略 -->
<bean id="tokenService" class="com.mote.wx.service.TokenService">
</bean>
<!-- spring自带的定时刷新任务 -->
<task:scheduled-tasks>
   <!-- 程序启动5秒后执行方法,之后每隔一小时执行 -->
<task:scheduled ref="tokenService" method="flush" initial-delay="5000" fixed-delay="3600000" />
<!-- <task:scheduled ref="statJob" method="statLgj" cron="0 59 23 * * ?" /> -->
</task:scheduled-tasks>

 

2017-08-22 01:52:25 phil_jing 阅读数 11898

本部分需要用到微信的JS-SDK,微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。

通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

官方文档

一、JS-SDK引入

1.先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”,和网页授权一样只是个域名。

2.在需要调用JS接口的页面引入如下JS文件之一

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

二、通过config接口注入权限验证配置

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名
    jsApiList: [] // 必填,需要使用的JS接口列表
});

 

首先生成这个signature之前需要获取到一个临时票据jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,同样也需要个中控服务器控制刷新。

1、获取临时票据

封装返回结果
package com.phil.wechatauth.model.resp;

import com.phil.common.result.ResultState;

/**
 * jsapi_ticket是公众号用于调用微信JS接口的临时票据
 * @author phil
 * @date  2017年8月21日
 *
 */
public class JsapiTicket extends ResultState {

	/**
	 * 
	 */
	private static final long serialVersionUID = -357009110782376503L;
	
	private String ticket; //jsapi_ticket
	
	private String expires_in;

	public String getTicket() {
		return ticket;
	}

	public void setTicket(String ticket) {
		this.ticket = ticket;
	}

	public String getExpires_in() {
		return expires_in;
	}

	public void setExpires_in(String expires_in) {
		this.expires_in = expires_in;
	}
}
获取方法
	/**
	 * 获取jsapi_ticket 调用微信JS接口的临时票据
	 * @return
	 */
	public String getTicket(String accessToken) {
		JsapiTicket jsapiTicket = null;
		Map<String,String> params = new TreeMap<String,String>();
		params.put("access_token",accessToken);
		params.put("type", "jsapi");
		String result = HttpReqUtil.HttpDefaultExecute(HttpReqUtil.GET_METHOD, WechatConfig.GET_TICKET_URL, params,"");
		if(StringUtils.isNotBlank(result)){
			jsapiTicket = JsonUtil.fromJson(result, JsapiTicket.class);
		}
		if(jsapiTicket.getErrcode()==0){
			return jsapiTicket.getTicket();
		}
		return null;
	}

2、生成签名并返回参数

signature生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。

string1示例如下

jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value

这里有个坑,页面是nonceStr,但是签名的字段是noncestr,注意大小写

简单封装下JS-SDK config配置信息

package com.phil.wechatauth.model.resp;

/**
 * JS-SDK的页面配置信息
 * @author phil
 * @date 2017年8月22日
 *
 */
public class JsWechatConfig {

	private String appId;

	private long timestamp;

	private String noncestr;

	private String signature;

	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;
	}
}

添加配置信息到页面

/**
 * 
 */
package com.phil.wechatauth.controller;

import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.phil.common.config.SystemConfig;
import com.phil.common.config.WechatConfig;
import com.phil.common.util.DateTimeUtil;
import com.phil.common.util.PayUtil;
import com.phil.common.util.SignatureUtil;
import com.phil.wechatauth.model.resp.JsWechatConfig;
import com.phil.wechatauth.service.WechatAuthService;

/**
 * JS-SDK
 * @author phil
 * @date  2017年8月21日
 *
 */
@Controller
@RequestMapping("/auth")
public class WechatAuthController {
	
	@Autowired
	private WechatAuthService wechatAuthService;
	
	/**
	 * 获取地理位置
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/getLocation")
	public String getLocation(HttpServletRequest request) throws Exception{
		JsWechatConfig jsWechatConfig = new JsWechatConfig();
		jsWechatConfig.setAppId(WechatConfig.APP_ID);
		jsWechatConfig.setTimestamp(DateTimeUtil.currentTime());
		jsWechatConfig.setNoncestr(PayUtil.createNonceStr());
		SortedMap<Object,Object> map = new TreeMap<Object,Object>();
		map.put("jsapi_ticket", wechatAuthService.getTicket(wechatAuthService.findlastestToken()));
		map.put("noncestr", jsWechatConfig.getNoncestr());
		map.put("timestamp", jsWechatConfig.getTimestamp());
		map.put("url", request.getRequestURL().toString());
		String signature = SignatureUtil.createSha1Sign(map, null, SystemConfig.CHARACTER_ENCODING);
		jsWechatConfig.setSignature(signature);
		request.setAttribute("jsWechatConfig", jsWechatConfig);
		return "wechatauth/getLocation";
	}
}

签名方法

	/**
	 * 通过Map<SortedMap,Object>中的所有元素参与签名
	 * 
	 * @param map 待参与签名的map集合
	 * @params apikey apikey中 如果为空则不参与签名,如果不为空则参与签名
	 * @return
	 */
	public static String createSha1Sign(SortedMap<Object, Object> map, String apiKey, String characterEncoding) {
		String result = notSignParams(map, apiKey);
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("SHA-1");
			byte[] digest = md.digest(result.getBytes());
			result = byteToStr(digest);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return result;
	}

其他的签名方法

三、通过ready接口处理成功验证

以上执行完成,进入的完整的页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>获取地理位置</title>
<!-- 微信 js-sdk -->
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="http://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
</head>
<body>
	<br>
	<div class="container">
		<div class="form-group">
			<label for="firstname" class="col-sm-2 control-label">地址:</label>
			<div class="col-sm-10" id="item-ifo">
				<input type="text" value="" class="form-control"
					name="location.address" id="address" placeholder="正在获取地理位置" tabindex="1" autocomplete="off" />
				<div class="i-name ico" id="i-name"></div>
			</div>
		</div>
	</div>

</body>
<script type="text/javascript">
	wx.config({
	    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
	    appId: '${jsWechatConfig.appId}', // 必填,公众号的唯一标识
	    timestamp: '${jsWechatConfig.timestamp}' , // 必填,生成签名的时间戳
	    nonceStr: '${jsWechatConfig.noncestr}', // 必填,生成签名的随机串
	    signature: '${jsWechatConfig.signature}',// 必填,签名,见附录1
	    jsApiList: [ 'checkJsApi', 'openLocation', 'getLocation'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
	});
	
	wx.checkJsApi({
	    jsApiList: ['getLocation'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
	    success: function(res) {
	    	if (res.checkResult.getLocation == false) {  
                alert('你的微信版本太低,不支持微信JS接口,请升级到最新的微信版本!');  
                return;  
         }
	    }
	});
	var latitude;  
    var longitude;  
    var speed;  
    var accuracy; 
	wx.ready(function(){
	    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
		wx.getLocation({  
            success : function(res) {  
                latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90  
                longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。  
                speed = res.speed; // 速度,以米/每秒计  
                accuracy = res.accuracy; // 位置精度  
                alert(latitude);  
                alert(accuracy);
            },  
            cancel : function(res) {  
                alert('未能获取地理位置');  
            }
        });  
	});
	
	wx.error(function(res){
	    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
		alert("验证出错");  
	});
</script>
</html>

可以通过微信官方提供的微信web开发者工具调试

扫一扫加群

 

2017-07-11 19:12:44 xufangfang99 阅读数 430

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

2.微信sdk帮助文档
http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
3.根据基本配置里面的
 appid
 AppSecret
4.到开发者工具-在线接口调试工具
https://mp.weixin.qq.com/debug
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=secret 
生成access_token
 date
5.根据这两个值到
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=你的access_token&type=jsapi


生成json数据 ticket也就是jsapi_ticket


6.到
http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
进行其他变量的获取
signature
noncestr
timestamp


7.进行配置
8.进行调用
2017-08-14 17:46:05 lwx0313 阅读数 14548


接收component_verify_ticket

在第三方平台创建审核通过后,微信服务器会向其“授权事件接收URL”每隔10分钟定时推送component_verify_ticket。第三方平台方在收到ticket推送后也需进行解密(详细请见【消息加解密接入指引】),接收到后必须直接返回字符串success。

POST数据示例
<xml>
<AppId></AppId>
<CreateTime>1413192605 </CreateTime>
<InfoType> </InfoType>
<ComponentVerifyTicket> </ComponentVerifyTicket>
</xml>

接收post请求的xml

第一坑:微信发送的请求中一共有5个参数

@RequestMapping(value = "/getComponentVerifyTicket")
@ResponseBody
public String getComponentVerifyTicket(@RequestParam("timestamp")String timestamp, @RequestParam("nonce")String nonce,
                                        @RequestParam("msg_signature")String msgSignature, @RequestBody String postData){


时间戳 timestamp,随机数nonce , encrypt_type(加密类型,为aes)和msg_signature(消息体签名,用于验证消息体的正确性)以及xml内容



第二坑:对xml进行解密(整个项目中最恶心的坑)

下载官方demo
java的文件夹

src下的官方demo

import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import com.qq.weixin.mp.aes.WXBizMsgCrypt;

public class Program {

    public static void main(String[] args) throws Exception {

        //
        // 第三方回复公众平台
        //

        // 需要加密的明文
        String encodingAesKey = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG";
        String token = "pamtest";
        String timestamp = "1409304348";
        String nonce = "xxxxxx";
        String appId = "wxb11529c136998cb6";
        String replyMsg = " 中文<xml><ToUserName><![CDATA[oia2TjjewbmiOUlr6X-1crbLOvLw]]></ToUserName><FromUserName><![CDATA[gh_7f083739789a]]></FromUserName><CreateTime>1407743423</CreateTime><MsgType><![CDATA[video]]></MsgType><Video><MediaId><![CDATA[eYJ1MbwPRJtOvIEabaxHs7TX2D-HV71s79GUxqdUkjm6Gs2Ed1KF3ulAOA9H1xG0]]></MediaId><Title><![CDATA[testCallBackReplyVideo]]></Title><Description><![CDATA[testCallBackReplyVideo]]></Description></Video></xml>";

        WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
        String mingwen = pc.encryptMsg(replyMsg, timestamp, nonce);
        System.out.println("加密后: " + mingwen);

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        StringReader sr = new StringReader(mingwen);
        InputSource is = new InputSource(sr);
        Document document = db.parse(is);

        Element root = document.getDocumentElement();
        NodeList nodelist1 = root.getElementsByTagName("Encrypt");
        NodeList nodelist2 = root.getElementsByTagName("MsgSignature");

        String encrypt = nodelist1.item(0).getTextContent();
        String msgSignature = nodelist2.item(0).getTextContent();

        String format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>";
        String fromXML = String.format(format, encrypt);

        //
        // 公众平台发送消息给第三方,第三方处理
        //

        // 第三方收到公众号平台发送的消息
        String result2 = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);
        System.out.println("解密后明文: " + result2);

        //pc.verifyUrl(null, null, null, null);
    }
}



先把 encodingAesKey , token , timestamp , nonce , appId , replyMsg , msgSignature 都替换成你自己的参数

前两个参数在官网 管理中心-平台详情



因为只做解密,所以去掉不必要的代码

public class Program {

    public static void main(String[] args) throws Exception {
        // 需要加密的明文
        String encodingAesKey = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG";
        String token = "pamtest";
        String timestamp = "1409304348";
        String nonce = "xxxxxx";
        String appId = "wxb11529c136998cb6";
        String replyMsg = " 中文<xml><ToUserName><![CDATA[oia2TjjewbmiOUlr6X-1crbLOvLw]]></ToUserName><FromUserName><![CDATA[gh_7f083739789a]]></FromUserName><CreateTime>1407743423</CreateTime><MsgType><![CDATA[video]]></MsgType><Video><MediaId><![CDATA[eYJ1MbwPRJtOvIEabaxHs7TX2D-HV71s79GUxqdUkjm6Gs2Ed1KF3ulAOA9H1xG0]]></MediaId><Title><![CDATA[testCallBackReplyVideo]]></Title><Description><![CDATA[testCallBackReplyVideo]]></Description></Video></xml>";

        WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);

        String msgSignature = nodelist2.item(0).getTextContent();

        String result2 = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);
        System.out.println("解密后明文: " + result2);

        //pc.verifyUrl(null, null, null, null);
    }
}

把replyMsg换成微信传过来的xml密文,msgSignature换成微信请求传过来的参数msg_signature

如果出现java.security.InvalidKeyException: Illegal key size这个异常,恭喜你,掉进全是屎的坑里了

正常来讲参数都正确的话到这里解密就成功了run一下main方法
如果出现类似xml解析失败什么的,把xml里的AppId手动替换成ToUserName再试一次

对解密成功后的xml进行解析,我是用以前微信支付的工具把xml转成map再提取参数
需要的拿去

    public static Map<String, String> xmlToMap(String strXML) throws Exception {
        try {
            Map<String, String> data = new HashMap<String, String>();
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    Element element = (Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                stream.close();
            } catch (Exception ex) {
                // do nothing
            }
            return data;
        } catch (Exception ex) {
//            WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
            throw ex;
        }

    }

然后提取出ComponentVerifyTicket,并保存(之后要用)
怎么保存随意,数据库也好,缓存也好,用静态类存一下也行

ComponentInfo.componentVerifyTicket = xmlMap.get("ComponentVerifyTicket");

微信小程序开发二

阅读数 517

没有更多推荐了,返回首页