今天打算开发一个微信公众平台的一个阅读功能,使用开发者模式,第一个件就是要通过验证,就是token的验证.
我写的东西比较直接没有过多的解释性语言,如果有疑问可以通过评论来讨论一下.
接口开发一定要先看好接口说明,这个是很重要的,你对接口文档的理解直接影响到你的接口开发速度与质量.
开发工具:eclipse 3.5
使用技术:struts2 , spring 3.0 , hibernate 3.3 ,dom4j 等等
测试网址(伪): http://www.xyz.com/weixin_msg.action
测试token: token(您在使用的时候别忘了换成你自己的.)
===========接===口===说===明=============================
网址接入
公众平台用户提交信息后,微信服务器将发送GET请求到填写的URL上,并且带上四个参数:
参数 | 描述 |
---|---|
signature | 微信加密签名 |
timestamp | 时间戳 |
nonce | 随机数 |
echostr | 随机字符串 |
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,否则接入失败。
signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
加密/校验流程:
1. 将token、timestamp、nonce三个参数进行字典序排序
2. 将三个参数字符串拼接成一个字符串进行sha1加密
3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
=====================================================
action代码.我使用的是struts2所以是action.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringBufferInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.xyz.bbs.weixin.utils.WeixinMessageDigestUtil;
import com.xyz.framework.utils.MessageDigestUtil;
import com.xyz.framework.web.BaseAction;
@SuppressWarnings("serial")
@Controller("WeixinActionId")
@Scope("prototype")
public class WeixinAction extends BaseAction {
private static final String TOKEN = "token";
private static final String GET = "GET";
private String signature;
private String timestamp;
private String nonce;
private String echostr;
/**
* 微信回调方法、包括doGet & doPost
* @return
*/
public String msg(){
if (GET.equals(getRequest().getMethod())) {
//get
doget();
}else {
//post }
//为什么返回null?
return null;
}
/**
* get方式验证token
*/
public void doget(){
logger.debug("signature" + signature);
logger.debug("timestamp" + timestamp);
logger.debug("nonce" + nonce);
logger.debug("echostr" + echostr); Arrays.sort(ArrTmp);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < ArrTmp.length; i++) {
sb.append(ArrTmp[i]);
}
String pwd = WeixinMessageDigestUtil.getInstance().encipher(sb.toString()); if(pwd.equals(signature)){
if(!"".equals(echostr) && echostr != null){
try {
System.out.println("response");
this.getResponse().getWriter().write(echostr);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//一下代码不用看的.
//getter && setter
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getNonce() {
return nonce;
}
public void setNonce(String nonce) {
this.nonce = nonce;
}
public String getEchostr() {
return echostr;
}
public void setEchostr(String echostr) {
this.echostr = echostr;
}
}
加密工具类
import java.security.*;
import java.util.Arrays;
/*
* SHA1 水印算法工具类
* AJ 2013-04-12
*/
public final class WeixinMessageDigestUtil {
private static final WeixinMessageDigestUtil _instance = new WeixinMessageDigestUtil();
private MessageDigest alga;
private WeixinMessageDigestUtil() {
try {
alga = MessageDigest.getInstance("SHA-1");
} catch(Exception e) {
throw new InternalError("init MessageDigest error:" + e.getMessage());
}
}
public static WeixinMessageDigestUtil getInstance() {
return _instance;
}
public static String byte2hex(byte[] b) {
String des = "";
String tmp = null;
for (int i = 0; i < b.length; i++) {
tmp = (Integer.toHexString(b[i] & 0xFF));
if (tmp.length() == 1) {
des += "0";
}
des += tmp;
}
return des;
}
public String encipher(String strSrc) {
String strDes = null;
byte[] bt = strSrc.getBytes();
alga.update(bt);
strDes = byte2hex(alga.digest()); //to HexString
return strDes;
}
public static void main(String[] args) {
String signature="b7982f21e7f18f640149be5784df8d377877ebf9";
String timestamp="1365760417";
String nonce="1365691777";
String[] ArrTmp = { "token", timestamp, nonce };
Arrays.sort(ArrTmp);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < ArrTmp.length; i++) {
sb.append(ArrTmp[i]);
}
String pwd =WeixinMessageDigestUtil.getInstance().encipher(sb.toString());
if (signature.equals(pwd)) {
System.out.println("token 验证成功~!");
}else {
System.out.println("token 验证失败~!");
}
}
}
服务搭建完成之后就可以进行测试了,这个测试方法就不用我写了吧..
看到他说明你成功了.
最后简单说一下为什么action返回的是null而不是一个String.
大家都之后默认写struts2的时候需要指定返回路径,通常使用String来做.struts会根据你所返回的值去查找对应的页面.返回null就是因为微信接口协议,协议中说了echostr参数要远洋返回,如果是使用浏览器来看的话页面只有echostr的值,没有其他的字符.直接返回response,到页面就输出print了.