前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java微信公众平台开发_02_启用服务器配置

Java微信公众平台开发_02_启用服务器配置

作者头像
shirayner
发布2018-08-10 10:52:01
8.3K0
发布2018-08-10 10:52:01
举报
文章被收录于专栏:Java成神之路Java成神之路

一、准备阶段

需要准备事项:

1.一个能在公网上访问的项目:

                     见:【  Java微信公众平台开发_01_本地服务器映射外网  】

2.一个微信公众平台账号: 

                     去注册:(https://mp.weixin.qq.com/

3.策略文件

                     见:【 Java企业微信开发_Exception_02_java.security.InvalidKeyException: Illegal key size 】

4.微信官方消息加解密工具包

需要下载微信官方的消息加解密的工具包,主要是AES加密工具。由于这是企业微信的加解密包,因此我们后面还需要对这个加解密包进行一些修改。

 下载地址:https://wximg.gtimg.com/shake_tv/mpwiki/cryptoDemo.zip

 下载完将其添加进工程中:

二、填写服务器配置

1.记住 AppID 和 AppSecret

登录微信公众平台,开发—>基本配置—>公众号开发信息

2.设置IP白名单

(1)登录微信公众平台,开发—>基本配置—>公众号开发信息—>ip白名单—>查看—>修改

(2)需要将服务器的公网ip添加进去。若需要添加多个ip,则每行添加一个ip即可。

(3)查询服务器的公网ip:

          window系统: 直接百度搜索ip即可

          Linux系统: 参见【  Linux_服务器_01_查看公网IP  】     

3.填写服务器配置

登录微信公众平台,开发—>基本配置—>服务器配置—>修改配置

3.1 URL:

开发者用来接收微信消息和事件的接口URL 。在三种情况下会请求这个URL:

(1)回调模式:

填写完服务器配置,点击提交,微信服务器将发送GET请求到填写的服务器地址URL上,并携带上四个参数 signature 、timestamp、nonce、echostr

(2)接收消息:

当用户发送消息给公众号时,消息将被以POST方式推送到到填写的服务器地址URL上,

在安全模式(推荐)下,携带上六个参数 signature 、timestamp、nonce、openid、encrypt_type(加密类型,为aes)和msg_signature(消息体签名,用于验证消息体的正确性)

在明文模式(默认)下,携带上六个参数 signature 、timestamp、nonce、openid

(3)接收事件

当特定的用户操作引发事件推送时,(如用户点击某个click菜单按钮时),事件将被以POST方式推送到到填写的服务器地址URL上。 请求参数  同  接受消息

3.2 Token:

随机填写,要与代码中保持一致。生成加解密工具类、生成签名 时会用到

3.3 EncodingAESKey:

随机生成,要与代码中保持一致,生成加解密工具类时会用到。EncodingAESKey即消息加解密Key,长度固定为43个字符,从a-z,A-Z,0-9共62个字符中选取。

3.4 消息加解密方式

这里选择安全模式,这样在接收消息和事件时,都需要进行消息加解密。若选明文模式,则在接收消息和事件时,都不需要进行消息加解密。

三、验证服务器地址的有效性

1. 设置失败

填写完服务器配置后,这时我们点击提交,会提示设置失败。这是因为我们点击提交后,微信服务器将发送GET请求到填写的服务器地址URL上,并携带上四个参数 signature 、timestamp、nonce、echostr ,开发者接收到者四个参数之后,需要对这四个参数与token一起 进行签名校验。

2.签名校验的流程

(1)将token、timestamp、nonce三个参数进行字典序排序

(2)将三个参数字符串拼接成一个字符串进行sha1加密 得到一个签名signature1

(3)开发者将获得加密后的字符串signature1与signature进行比较

(4)若二者相同,则认为此次GET请求来自微信服务器,可原样返回echostr参数内容,配置成功。

         若二者不相同,则认为此次GET请求不是来自微信服务器,不可原样返回echostr参数内容,配置失败。

总结:用 token、timestamp、nonce 生成一个签名signature1,并与signature比较,若相同,则原样返回echostr,若不同则配置失败。

3.微信服务器怎么判断签名校验是否成功?

若微信服务器收到原样的echostr,则任务校验成功。也就是说如果你收到signature 、timestamp、nonce、echostr 后,什么都不做,就只原样返回一个echostr,微信服务器还是认为你校验成功了。

4.签名校验的代码实现

4.1  用SHA1算法生成安全签名 signature1
/**
     * 微信公众号SHA1加密算法
     * 用SHA1算法生成安全签名
     * @param token 票据
     * @param timestamp 时间戳
     * @param nonce 随机字符串
     * @return 安全签名
     * @throws AesException 
     */
    public static String getSHA1_WXGZ(String token, String timestamp, String nonce) throws AesException
              {
        try {
            String[] array = new String[] { token, timestamp, nonce };
            StringBuffer sb = new StringBuffer();
            //1.将token、timestamp、nonce三个参数进行字典序排序
            Arrays.sort(array);
            
            //2.将三个参数字符串拼接成一个字符串进行sha1加密
            for (int i = 0; i < 3; i++) {
                sb.append(array[i]);
            }
            String str = sb.toString();
            //2.2 SHA1签名生成
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();

            StringBuffer hexstr = new StringBuffer();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
            return hexstr.toString();
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.ComputeSignatureError);
        }
    }
}
4.2 验证signature1是否与signature相同
/**
     * 
     * 验证URL
     * @param msgSignature 
     * @param timeStamp 时间戳,对应URL参数的timestamp
     * @param nonce 随机串,对应URL参数的nonce
     * @param echoStr 随机串,对应URL参数的echostr
     * 
     * @return 解密之后的echostr
     * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
     */
    /**
     * @desc :微信公众号  验证url
     *  
     * @param msgSignature  签名串,对应URL参数的msg_signature
     * @param token 公众平台上,开发者设置的token
     * @param timeStamp   时间戳,对应URL参数的timestamp
     * @param nonce 随机数,对应URL参数的nonce
     * @return
     *    true  验证成功
     * @throws AesException boolean
     */
    public boolean verifyUrl_WXGZ(String msgSignature, String token , String timeStamp, String nonce) throws AesException {
        //1.进行SHA1加密
        String signature = SHA1.getSHA1_WXGZ(token, timeStamp, nonce);

        //2.验证 token、timestamp、nonce进行SHA1加密生成的signature 是否与url传过来msgSignature相同
        if (!signature.equals(msgSignature)) {
            throw new AesException(AesException.ValidateSignatureError);
        //3.若相同,则url验证成功,返回true
        }else{
            return true;
        }
    }
4.3 在servlet的doGet方法中进行url的校验
    //1.接收  回调模式  的请求
    protected void doGet(HttpServletRequest request, HttpServletResponse response)  {
        logger.info("get--------------");
        //一、校验URL
        //1.准备校验参数
        // 微信加密签名  
        String msgSignature = request.getParameter("signature");  
        // 时间戳  
        String timeStamp = request.getParameter("timestamp");  
        // 随机数  
        String nonce = request.getParameter("nonce");  
        // 随机字符串  
        String echoStr = request.getParameter("echostr");  

        PrintWriter out=null;
        try {
            //2.校验url
            //2.1 创建加解密类
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(Env.TOKEN,Env.ENCODING_AES_KEY,Env.APP_ID);

            //2.2进行url校验
            //不抛异常就说明校验成功
            boolean mark= wxcpt.verifyUrl_WXGZ(msgSignature, Env.TOKEN, timeStamp, nonce);

            //2.3若校验成功,则原样返回 echoStr
            if (mark) {  
                out = response.getWriter(); 
                out.print(echoStr);  
            }



        } catch (AesException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (out != null) {
                out.close();  
                out = null;                       //释放资源
            }
        }
    }

 四、代码实现

1.微信配置类—Env.java

微信公众号接入配置类

package com.ray.weixin.gz.config;

/**@desc  : 微信公众号接入配置
 * 
 * @author: shirayner
 * @date  : 2017年9月27日 下午4:57:36
 */

public class Env {

    /**
     * 1. 企业应用接入秘钥相关
     */
    //public static final String APP_ID = "wx4dca3424bebef2cc";
   // public static final String APP_SECRET = "068e2599abf88ba78491a07906f3c56e";
  
    //测试号
    public static final String APP_ID = "wxa0064ea657f80062";
    public static final String APP_SECRET = "fcc960840df869ad1a46af7993784917";
    

    /**
     * 2.服务器配置:
     * 启用并设置服务器配置后,用户发给公众号的消息以及开发者需要的事件推送,将被微信转发到该URL中
     */
    public static final String TOKEN = "weixin";
    public static final String ENCODING_AES_KEY = "JvJ1Dww6tjUU2psC3pmokXvOHHfovfWP3LfX1xrriz1";
    
    
  

    
}

2.HTTP请求工具类—HttpHelper.java

package com.ray.weixin.gz.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;


/**
 * HTTP请求封装,建议直接使用sdk的API
 */
public class HttpHelper {

    /**
     * @desc :1.发起GET请求
     *  
     * @param url
     * @return JSONObject
     * @throws Exception 
     */
    public static JSONObject doGet(String url) throws Exception {

        //1.生成一个请求
        HttpGet httpGet = new HttpGet(url);
        //2.配置请求的属性
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();//2000
        httpGet.setConfig(requestConfig);

        //3.发起请求,获取响应信息    
        //3.1 创建httpClient 
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        try {
            //3.2 发起请求,获取响应信息    
            response = httpClient.execute(httpGet, new BasicHttpContext());

            //如果返回结果的code不等于200,说明出错了  
            if (response.getStatusLine().getStatusCode() != 200) {

                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
                        + ", url=" + url);
                return null;
            }
            //4.解析请求结果
            HttpEntity entity = response.getEntity();      //reponse返回的数据在entity中 
            if (entity != null) {
                String resultStr = EntityUtils.toString(entity, "utf-8");  //将数据转化为string格式  
                System.out.println("GET请求结果:"+resultStr);
                JSONObject result = JSON.parseObject(resultStr);    //将String转换为 JSONObject

                if(result.getInteger("errcode")==null) {
                    return result;
                }else if (0 == result.getInteger("errcode")) {
                    return result;
                }else {
                    System.out.println("request url=" + url + ",return value=");
                    System.out.println(resultStr);
                    int errCode = result.getInteger("errcode");
                    String errMsg = result.getString("errmsg");
                    throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                }
            }
        } catch (IOException e) {
            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (response != null) try {
                response.close();                     //释放资源

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }


    /** 2.发起POST请求
     * @desc :
     *  
     * @param url   请求url
     * @param data  请求参数(json)
     * @return
     * @throws Exception JSONObject
     */
    public static JSONObject doPost(String url, Object data) throws Exception {
        //1.生成一个请求
        HttpPost httpPost = new HttpPost(url);

        //2.配置请求属性
        //2.1 设置请求超时时间
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(100000).build();
        httpPost.setConfig(requestConfig);
        //2.2 设置数据传输格式-json
        httpPost.addHeader("Content-Type", "application/json");
        //2.3 设置请求参数
        StringEntity requestEntity = new StringEntity(JSON.toJSONString(data), "utf-8");
        httpPost.setEntity(requestEntity);

        //3.发起请求,获取响应信息    
        //3.1 创建httpClient 
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;

        try {


            //3.3 发起请求,获取响应
            response = httpClient.execute(httpPost, new BasicHttpContext());

            if (response.getStatusLine().getStatusCode() != 200) {

                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
                        + ", url=" + url);
                return null;
            }

            //获取响应内容
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String resultStr = EntityUtils.toString(entity, "utf-8");
                System.out.println("POST请求结果:"+resultStr);

                //解析响应内容
                JSONObject result = JSON.parseObject(resultStr);

                if(result.getInteger("errcode")==null) {
                    return result;
                }else if (0 == result.getInteger("errcode")) {
                    return result;
                }else {
                    System.out.println("request url=" + url + ",return value=");
                    System.out.println(resultStr);
                    int errCode = result.getInteger("errcode");
                    String errMsg = result.getString("errmsg");
                    throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                }
            }
        } catch (IOException e) {
            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (response != null) try {
                response.close();              //释放资源

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    /**
     * @desc : 3.上传文件
     *  
     * @param url   请求url
     * @param file  上传的文件
     * @return
     * @throws Exception JSONObject
     */
    public static JSONObject uploadMedia(String url, File file) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
        httpPost.setConfig(requestConfig);

        HttpEntity requestEntity = MultipartEntityBuilder.create().addPart("media",
                new FileBody(file, ContentType.APPLICATION_OCTET_STREAM, file.getName())).build();
        httpPost.setEntity(requestEntity);

        try {
            response = httpClient.execute(httpPost, new BasicHttpContext());

            if (response.getStatusLine().getStatusCode() != 200) {

                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
                        + ", url=" + url);
                return null;
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String resultStr = EntityUtils.toString(entity, "utf-8");

                JSONObject result = JSON.parseObject(resultStr);
                //上传临时素材成功
                if (result.getString("errcode")== null) {
                    // 成功
                    //result.remove("errcode");
                    //result.remove("errmsg");
                    return result;
                } else {
                    System.out.println("request url=" + url + ",return value=");
                    System.out.println(resultStr);
                    int errCode = result.getInteger("errcode");
                    String errMsg = result.getString("errmsg");
                    throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                }
            }
        } catch (IOException e) {
            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (response != null) try {
                response.close();                  //释放资源


            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    /**
     * @desc : 4.下载文件 -get
     *  
     * @param url  请求url
     * @param fileDir  下载路径
     * @return
     * @throws Exception File
     */
    public static File downloadMedia(String url, String fileDir) throws Exception  {
        //1.生成一个请求
        HttpGet httpGet = new HttpGet(url);
        //2.配置请求属性
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(100000).build();
        httpGet.setConfig(requestConfig);

        //3.发起请求,获取响应信息    
        //3.1 创建httpClient 
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;

        //4.设置本地保存的文件  
        //File file = new File(fileDir);
        File file = null;
        try {
            //5. 发起请求,获取响应信息    
            response = httpClient.execute(httpGet, new BasicHttpContext());
            System.out.println("HttpStatus.SC_OK:"+HttpStatus.SC_OK);  
            System.out.println("response.getStatusLine().getStatusCode():"+response.getStatusLine().getStatusCode());  
            System.out.println("http-header:"+JSON.toJSONString( response.getAllHeaders() ));  
            System.out.println("http-filename:"+getFileName(response) );  

            //请求成功  
            if(HttpStatus.SC_OK==response.getStatusLine().getStatusCode()){  

                //6.取得请求内容  
                HttpEntity entity = response.getEntity();  

                if (entity != null) {  
                    //这里可以得到文件的类型 如image/jpg /zip /tiff 等等 但是发现并不是十分有效,有时明明后缀是.rar但是取到的是null,这点特别说明  
                    System.out.println(entity.getContentType());  
                    //可以判断是否是文件数据流  
                    System.out.println(entity.isStreaming());  

                    //6.1 输出流
                    //6.1.1获取文件名,拼接文件路径
                    String fileName=getFileName(response);
                    fileDir=fileDir+fileName;
                    file = new File(fileDir);
                    //6.1.2根据文件路径获取输出流
                    FileOutputStream output = new FileOutputStream(file);  

                    //6.2 输入流:从钉钉服务器返回的文件流,得到网络资源并写入文件  
                    InputStream input = entity.getContent();  

                    //6.3 将数据写入文件:将输入流中的数据写入到输出流
                    byte b[] = new byte[1024];  
                    int j = 0;  
                    while( (j = input.read(b))!=-1){  
                        output.write(b,0,j);  
                    }  
                    output.flush();  
                    output.close();   
                }  
                if (entity != null) {  
                    entity.consumeContent();  
                }  
            }  
        } catch (IOException e) {
            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (response != null) try {
                response.close();                       //释放资源


            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return file;
    }


    /**
     * @desc : 5.下载文件 - post
     *  
     * @param url  请求url
     * @param data  post请求参数
     * @param fileDir 文件下载路径
     * @return
     * @throws Exception File
     */
    public static File downloadMedia(String url, Object data, String fileDir) throws Exception  {
        //1.生成一个请求
        HttpPost httpPost = new HttpPost(url);

        //2.配置请求属性
        //2.1 设置请求超时时间
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(100000).build();
        httpPost.setConfig(requestConfig);
        //2.2 设置数据传输格式-json
        httpPost.addHeader("Content-Type", "application/json");
        //2.3 设置请求参数
        StringEntity requestEntity = new StringEntity(JSON.toJSONString(data), "utf-8");
        httpPost.setEntity(requestEntity);

        //3.发起请求,获取响应信息    
        //3.1 创建httpClient 
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;

        //4.设置本地保存的文件  
        //File file = new File(fileDir);
        File file = null;
        try {
            //5. 发起请求,获取响应信息    
            response = httpClient.execute(httpPost, new BasicHttpContext());
            System.out.println("HttpStatus.SC_OK:"+HttpStatus.SC_OK);  
            System.out.println("response.getStatusLine().getStatusCode():"+response.getStatusLine().getStatusCode());  
            System.out.println("http-header:"+JSON.toJSONString( response.getAllHeaders() ));  
            System.out.println("http-filename:"+getFileName(response) );  

            //请求成功  
            if(HttpStatus.SC_OK==response.getStatusLine().getStatusCode()){  

                //6.取得请求内容  
                HttpEntity entity = response.getEntity();  

                if (entity != null) {  
                    //这里可以得到文件的类型 如image/jpg /zip /tiff 等等 但是发现并不是十分有效,有时明明后缀是.rar但是取到的是null,这点特别说明  
                    System.out.println(entity.getContentType());  
                    //可以判断是否是文件数据流  
                    System.out.println(entity.isStreaming());  

                    //6.1 输出流
                    //6.1.1获取文件名,拼接文件路径
                    String fileName=getFileName(response);
                    fileDir=fileDir+fileName;
                    file = new File(fileDir);
                    //6.1.2根据文件路径获取输出流
                    FileOutputStream output = new FileOutputStream(file);  

                    //6.2 输入流:从钉钉服务器返回的文件流,得到网络资源并写入文件  
                    InputStream input = entity.getContent();  

                    //6.3 将数据写入文件:将输入流中的数据写入到输出流
                    byte b[] = new byte[1024];  
                    int j = 0;  
                    while( (j = input.read(b))!=-1){  
                        output.write(b,0,j);  
                    }  
                    output.flush();  
                    output.close();   
                }  
                if (entity != null) {  
                    entity.consumeContent();  
                }  
            }  
        } catch (IOException e) {
            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (response != null) try {
                response.close();                       //释放资源


            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return file;
    }


    /** 5. 获取response header中Content-Disposition中的filename值 
     * @desc :
     *  
     * @param response  响应
     * @return String
     */
    public static String getFileName(HttpResponse response) {  
        Header contentHeader = response.getFirstHeader("Content-Disposition");  
        String filename = null;  
        if (contentHeader != null) {  
            HeaderElement[] values = contentHeader.getElements();  
            if (values.length == 1) {  
                NameValuePair param = values[0].getParameterByName("filename");  
                if (param != null) {  
                    try {  
                        //filename = new String(param.getValue().toString().getBytes(), "utf-8");  
                        //filename=URLDecoder.decode(param.getValue(),"utf-8");  
                        filename = param.getValue();  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            }  
        }  
        return filename;  
    }  



}

3.Token相关工具类—AuthHelper.java

package com.ray.weixin.gz.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.alibaba.fastjson.JSONObject;
import com.ray.weixin.gz.config.Env;


/**
 * 微信公众号 Token、配置工具类
 * @desc  : AccessToken、Jsticket 、Jsapi
 * 
 * @author: shirayner
 * @date  : 2017年9月27日 下午5:00:25
 */
public class AuthHelper {
    private static final Logger logger = LogManager.getLogger(AuthHelper.class);

    //1.获取access_token的接口地址,有效期为7200秒
    private static final String GET_ACCESSTOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; 
    //2.获取getJsapiTicket的接口地址,有效期为7200秒 
    private static final String GET_JSAPITICKET_URL="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi"; 

    //3.通过code换取网页授权access_token
    private static final String GET_ACCESSTOKEN_BYCODE_URL="https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; 


    /**
     * @desc :1.获取access_token 
     *  
     * @param appId  第三方用户唯一凭证
     * @param appSecret  第三方用户唯一凭证密钥,即appsecret
     * 
     * @return
     *      access_token    获取到的凭证
     *      expires_in    凭证有效时间,单位:秒
     * @throws Exception String
     */
    public static String getAccessToken(String appId,String appSecret) throws Exception {
        //1.获取请求url
        String url=GET_ACCESSTOKEN_URL.replace("APPID", appId).replace("APPSECRET", appSecret);

        //2.发起GET请求,获取返回结果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析结果,获取accessToken
        String accessToken="";  
        if (null != jsonObject) {  
            //4.错误消息处理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功获取accessToken
            }else {
                accessToken=jsonObject.getString("access_token");
            }  
        }  


        return accessToken;
    }


    /**
     * @desc :2.获取JsapiTicket
     *  
     * @param accessToken  有效凭证
     * @return
     * @throws Exception String
     */
    public static String getJsapiTicket(String accessToken) throws Exception {
        //1.获取请求url
        String url=GET_JSAPITICKET_URL.replace("ACCESS_TOKEN", accessToken);

        //2.发起GET请求,获取返回结果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析结果,获取accessToken
        String jsapiTicket="";  
        if (null != jsonObject) {  
            //4.错误消息处理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功获取jsapiTicket
            }else {
                jsapiTicket=jsonObject.getString("ticket");
            }  
        }  


        return jsapiTicket;
    }

    /**
     * @desc : 3.通过code换取网页授权access_token
     *  
     * @param appId  第三方用户唯一凭证
     * @param appSecret  第三方用户唯一凭证密钥,即appsecret
     * @param Code  code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
     * 
     * @return
     * access_token    网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
     * expires_in    access_token接口调用凭证超时时间,单位(秒)
     * refresh_token    用户刷新access_token
     * openid    用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
     * scope    用户授权的作用域,使用逗号(,)分隔
     * 
     * @throws Exception String
     */
    public static JSONObject getAccessTokenByCode(String appId,String appSecret,String code) throws Exception {
        //1.获取请求url
        String url=GET_ACCESSTOKEN_BYCODE_URL.replace("APPID", appId).replace("SECRET", appSecret).replace("CODE", code);

        //2.发起GET请求,获取返回结果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析结果,获取accessToken
        JSONObject returnJsonObject=null;
        if (null != jsonObject) {  
            //4.错误消息处理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功获取accessToken
            }else {
                returnJsonObject=jsonObject;
            }  
        }  


        return returnJsonObject;
    }


    /**
     * @desc :4.获取前端jsapi需要的配置参数
     *  
     * @param request
     * @return String
     */
    public static String getJsapiConfig(HttpServletRequest request){  

        //1.准备好参与签名的字段
        //1.1 url
        /* 
         *以http://localhost/test.do?a=b&c=d为例 
         *request.getRequestURL的结果是http://localhost/test.do 
         *request.getQueryString的返回值是a=b&c=d 
         */  
        String urlString = request.getRequestURL().toString();
        String queryString = request.getQueryString();
        String queryStringEncode = null;
        String url;
        if (queryString != null) {
            queryStringEncode = URLDecoder.decode(queryString);
            url = urlString + "?" + queryStringEncode;
        } else {
            url = urlString;
        }

        //1.2 noncestr
        String nonceStr=UUID.randomUUID().toString();      //随机数
        //1.3 timestamp
        long timeStamp = System.currentTimeMillis() / 1000;     //时间戳参数  

        String signedUrl = url;

        String accessToken = null;
        String ticket = null;

        String signature = null;       //签名


        try {  
            //1.4 jsapi_ticket
            accessToken=getAccessToken(Env.APP_ID, Env.APP_SECRET);  
            ticket=getJsapiTicket(accessToken);  

            //2.进行签名,获取signature
            signature=getSign(ticket,nonceStr,timeStamp,signedUrl);  


        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  

        logger.info("accessToken:"+accessToken);
        logger.info("ticket:"+ticket);
        logger.info("nonceStr:"+nonceStr);
        logger.info("timeStamp:"+timeStamp);
        logger.info("signedUrl:"+signedUrl);
        logger.info("signature:"+signature);
        logger.info("appId:"+Env.APP_ID);




        String configValue = "{signature:'" + signature + "',nonceStr:'" + nonceStr + "',timeStamp:'"
                + timeStamp + "',appId:'" + Env.APP_ID + "'}";
        logger.info("configValue:"+configValue);

        return configValue;  
    }  


    /**
     * @desc : 3.生成签名的函数 
     *  
     * @param ticket jsticket
     * @param nonceStr 随机串,自己定义
     * @param timeStamp 生成签名用的时间戳 
     * @param url 需要进行免登鉴权的页面地址,也就是执行dd.config的页面地址 
     * @return
     * @throws Exception String
     */

    public static String getSign(String jsTicket, String nonceStr, Long timeStamp, String url) throws Exception {  
        String plainTex = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp + "&url=" + url;
        System.out.println(plainTex);
        try {  
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(plainTex.getBytes("UTF-8"));
            return byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception(e.getMessage());  
        } catch (UnsupportedEncodingException e) {  
            throw new Exception(e.getMessage());  
        }  
    }  

    //将bytes类型的数据转化为16进制类型  
    private static String byteToHex(byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", new Object[] { Byte.valueOf(b) });
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }







}

4.验证URL的servlet—WeiXinServlet

package com.ray.weixin.gz.controller;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import com.ray.weixin.gz.config.Env;
import com.ray.weixin.gz.service.message.ReplyMessageService;



/**
 * Servlet implementation class WeiXinServlet
 */         
public class WeiXinServlet extends HttpServlet {
    private static final Logger logger = LogManager.getLogger(WeiXinServlet.class);



    private static final long serialVersionUID = 1L;

    /**
     * Default constructor. 
     */
    public WeiXinServlet() {
        // TODO Auto-generated constructor stub
    }

    //1.接收  回调模式  的请求
    protected void doGet(HttpServletRequest request, HttpServletResponse response)  {
        logger.info("get--------------");
        //一、校验URL
        //1.准备校验参数
        // 微信加密签名  
        String msgSignature = request.getParameter("signature");  
        // 时间戳  
        String timeStamp = request.getParameter("timestamp");  
        // 随机数  
        String nonce = request.getParameter("nonce");  
        // 随机字符串  
        String echoStr = request.getParameter("echostr");  

        PrintWriter out=null;
        try {
            //2.校验url
            //2.1 创建加解密类
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(Env.TOKEN,Env.ENCODING_AES_KEY,Env.APP_ID);

            //2.2进行url校验
            //不抛异常就说明校验成功
            String sEchoStr= wxcpt.verifyUrl_WXGZ(msgSignature, Env.TOKEN, timeStamp, nonce,echoStr);

            //2.3若校验成功,则原样返回 echoStr

            out = response.getWriter(); 
            out.print(sEchoStr);  




        } catch (AesException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (out != null) {
                out.close();  
                out = null;                       //释放资源
            }
        }
    }

    //2.接收  微信消息和事件  的请求
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("post--------------");
        //1.将请求、响应的编码均设置为UTF-8(防止中文乱码)  
        request.setCharacterEncoding("UTF-8");  
        response.setCharacterEncoding("UTF-8");  

        //2.调用消息业务类接收消息、处理消息  
        String respMessage = ReplyMessageService.reply(request);  

        //3.响应消息  
        PrintWriter out = response.getWriter();  
        out.print(respMessage);  
        out.close(); 



    }

}

5.微信公众号SHA1加密算法工具类—SHA1.java

此类是信官方的消息加解密的工具包中的一个类,我在原来的基础上增加了一个方法 getSHA1_WXGZ(String, String, String) 

/**
 * 对公众平台发送给公众账号的消息加解密示例代码.
 * 
 * @copyright Copyright (c) 1998-2014 Tencent Inc.
 */

// ------------------------------------------------------------------------

package com.qq.weixin.mp.aes;

import java.security.MessageDigest;
import java.util.Arrays;

/**
 * SHA1 class
 *
 * 计算公众平台的消息签名接口.
 */
class SHA1 {

    /**
     * 用SHA1算法生成安全签名
     * @param token 票据
     * @param timestamp 时间戳
     * @param nonce 随机字符串
     * @param encrypt 密文
     * @return 安全签名
     * @throws AesException 
     */
    public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
              {
        try {
            String[] array = new String[] { token, timestamp, nonce, encrypt };
            StringBuffer sb = new StringBuffer();
            // 字符串排序
            Arrays.sort(array);
            for (int i = 0; i < 4; i++) {
                sb.append(array[i]);
            }
            String str = sb.toString();
            // SHA1签名生成
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();

            StringBuffer hexstr = new StringBuffer();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
            return hexstr.toString();
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.ComputeSignatureError);
        }
    }
    
    /**
     * 微信公众号SHA1加密算法
     * 用SHA1算法生成安全签名
     * @param token 票据
     * @param timestamp 时间戳
     * @param nonce 随机字符串
     * @return 安全签名
     * @throws AesException 
     */
    public static String getSHA1_WXGZ(String token, String timestamp, String nonce) throws AesException
              {
        try {
            String[] array = new String[] { token, timestamp, nonce };
            StringBuffer sb = new StringBuffer();
            //1.将token、timestamp、nonce三个参数进行字典序排序
            Arrays.sort(array);
            
            //2.将三个参数字符串拼接成一个字符串进行sha1加密
            for (int i = 0; i < 3; i++) {
                sb.append(array[i]);
            }
            String str = sb.toString();
            //2.2 SHA1签名生成
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();

            StringBuffer hexstr = new StringBuffer();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
            return hexstr.toString();
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.ComputeSignatureError);
        }
    }
}

6.校验url—WXBizMsgCrypt.java

此类是信官方的消息加解密的工具包中的一个类,我在原来的基础上增加了一个方法  verifyUrl_WXGZ(String msgSignature, String token , String timeStamp, String nonce,String echoStr) 

/**
 * 对公众平台发送给公众账号的消息加解密示例代码.
 * 
 * @copyright Copyright (c) 1998-2014 Tencent Inc.
 */

// ------------------------------------------------------------------------

/**
 * 针对org.apache.commons.codec.binary.Base64,
 * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
 * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
 */
package com.qq.weixin.mp.aes;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

/**
 * 提供接收和推送给公众平台消息的加解密接口(UTF8编码的字符串).
 * <ol>
 *     <li>第三方回复加密消息给公众平台</li>
 *     <li>第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。</li>
 * </ol>
 * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案
 * <ol>
 *     <li>在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:
 *      http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html</li>
 *     <li>下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt</li>
 *     <li>如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件</li>
 *     <li>如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件</li>
 * </ol>
 */
public class WXBizMsgCrypt {
    static Charset CHARSET = Charset.forName("utf-8");
    Base64 base64 = new Base64();
    byte[] aesKey;
    String token;
    String corpId;

    /**
     * 构造函数
     * @param token 公众平台上,开发者设置的token
     * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey
     * @param corpId 企业的corpid
     * 
     * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
     */
    public WXBizMsgCrypt(String token, String encodingAesKey, String corpId) throws AesException {
        if (encodingAesKey.length() != 43) {
            throw new AesException(AesException.IllegalAesKey);
        }

        this.token = token;
        this.corpId = corpId;
        aesKey = Base64.decodeBase64(encodingAesKey + "=");
    }

    // 生成4个字节的网络字节序
    byte[] getNetworkBytesOrder(int sourceNumber) {
        byte[] orderBytes = new byte[4];
        orderBytes[3] = (byte) (sourceNumber & 0xFF);
        orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
        orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
        orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
        return orderBytes;
    }

    // 还原4个字节的网络字节序
    int recoverNetworkBytesOrder(byte[] orderBytes) {
        int sourceNumber = 0;
        for (int i = 0; i < 4; i++) {
            sourceNumber <<= 8;
            sourceNumber |= orderBytes[i] & 0xff;
        }
        return sourceNumber;
    }

    // 随机生成16位字符串
    String getRandomStr() {
        String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 16; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 对明文进行加密.
     * 
     * @param text 需要加密的明文
     * @return 加密后base64编码的字符串
     * @throws AesException aes加密失败
     */
    String encrypt(String randomStr, String text) throws AesException {
        ByteGroup byteCollector = new ByteGroup();
        byte[] randomStrBytes = randomStr.getBytes(CHARSET);
        byte[] textBytes = text.getBytes(CHARSET);
        byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
        byte[] corpidBytes = corpId.getBytes(CHARSET);

        // randomStr + networkBytesOrder + text + corpid
        byteCollector.addBytes(randomStrBytes);
        byteCollector.addBytes(networkBytesOrder);
        byteCollector.addBytes(textBytes);
        byteCollector.addBytes(corpidBytes);

        // ... + pad: 使用自定义的填充方式对明文进行补位填充
        byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
        byteCollector.addBytes(padBytes);

        // 获得最终的字节流, 未加密
        byte[] unencrypted = byteCollector.toBytes();

        try {
            // 设置加密模式为AES的CBC模式
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

            // 加密
            byte[] encrypted = cipher.doFinal(unencrypted);

            // 使用BASE64对加密后的字符串进行编码
            String base64Encrypted = base64.encodeToString(encrypted);

            return base64Encrypted;
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.EncryptAESError);
        }
    }

    /**
     * 对密文进行解密.
     * 
     * @param text 需要解密的密文
     * @return 解密得到的明文
     * @throws AesException aes解密失败
     */
    String decrypt(String text) throws AesException {
        byte[] original;
        try {
            // 设置解密模式为AES的CBC模式
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
            cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);

            // 使用BASE64对密文进行解码
            byte[] encrypted = Base64.decodeBase64(text);

            // 解密
            original = cipher.doFinal(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.DecryptAESError);
        }

        String xmlContent, from_corpid;
        try {
            // 去除补位字符
            byte[] bytes = PKCS7Encoder.decode(original);

            // 分离16位随机字符串,网络字节序和corpId
            byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);

            int xmlLength = recoverNetworkBytesOrder(networkOrder);

            xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
            from_corpid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
                    CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.IllegalBuffer);
        }

        // corpid不相同的情况
        if (!from_corpid.equals(corpId)) {
            throw new AesException(AesException.ValidateCorpidError);
        }
        return xmlContent;

    }

    /**
     * 将公众平台回复用户的消息加密打包.
     * <ol>
     *     <li>对要发送的消息进行AES-CBC加密</li>
     *     <li>生成安全签名</li>
     *     <li>将消息密文和安全签名打包成xml格式</li>
     * </ol>
     * 
     * @param replyMsg 公众平台待回复用户的消息,xml格式的字符串
     * @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp
     * @param nonce 随机串,可以自己生成,也可以用URL参数的nonce
     * 
     * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串
     * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
     */
    public String EncryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
        // 加密
        String encrypt = encrypt(getRandomStr(), replyMsg);

        // 生成安全签名
        if (timeStamp == "") {
            timeStamp = Long.toString(System.currentTimeMillis());
        }

        String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);

        // System.out.println("发送给平台的签名是: " + signature[1].toString());
        // 生成发送的xml
        String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
        return result;
    }

    /**
     * 检验消息的真实性,并且获取解密后的明文.
     * <ol>
     *     <li>利用收到的密文生成安全签名,进行签名验证</li>
     *     <li>若验证通过,则提取xml中的加密消息</li>
     *     <li>对消息进行解密</li>
     * </ol>
     * 
     * @param msgSignature 签名串,对应URL参数的msg_signature
     * @param timeStamp 时间戳,对应URL参数的timestamp
     * @param nonce 随机串,对应URL参数的nonce
     * @param postData 密文,对应POST请求的数据
     * 
     * @return 解密后的原文
     * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
     */
    public String DecryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
            throws AesException {

        // 密钥,公众账号的app secret
        // 提取密文
        Object[] encrypt = XMLParse.extract(postData);

        // 验证安全签名
        String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());

        // 和URL中的签名比较是否相等
        // System.out.println("第三方收到URL中的签名:" + msg_sign);
        // System.out.println("第三方校验签名:" + signature);
        if (!signature.equals(msgSignature)) {
            throw new AesException(AesException.ValidateSignatureError);
        }

        // 解密
        String result = decrypt(encrypt[1].toString());
        return result;
    }

    /**
     * 验证URL
     * @param msgSignature 签名串,对应URL参数的msg_signature
     * @param timeStamp 时间戳,对应URL参数的timestamp
     * @param nonce 随机串,对应URL参数的nonce
     * @param echoStr 随机串,对应URL参数的echostr,在企业微信中是加密过的,需要解密后返回给企业微信官方服务器
     * 
     * @return 解密之后的echostr
     * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
     */
    public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
            throws AesException {
        String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);

        if (!signature.equals(msgSignature)) {
            throw new AesException(AesException.ValidateSignatureError);
        }

        String result = decrypt(echoStr);
        return result;
    }


    /**
     * @desc :微信公众号  验证url
     *  
     * @param msgSignature  签名串,对应URL参数的msg_signature
     * @param token 公众平台上,开发者设置的token
     * @param timeStamp   时间戳,对应URL参数的timestamp
     * @param nonce 随机数,对应URL参数的nonce
     * @param echoStr 随机串,对应URL参数的echostr,在微信公众号中是明文的,直接原样返回给微信公众平台官方服务器
     * @return
     *    String  验证成功后,原样返回echoStr
     * @throws AesException   执行失败,请查看该异常的错误码和具体的错误信息
     */
    public String verifyUrl_WXGZ(String msgSignature, String token , String timeStamp, String nonce,String echoStr) throws AesException {
        //1.进行SHA1加密
        String signature = SHA1.getSHA1_WXGZ(token, timeStamp, nonce);

        //2.验证 token、timestamp、nonce进行SHA1加密生成的signature 是否与url传过来msgSignature相同
        if (!signature.equals(msgSignature)) {
            throw new AesException(AesException.ValidateSignatureError);

        }
        //3.若不抛异常,则url验证成功,原样返回echoStr
        String result = echoStr;
        return result;
    }


}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-11-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、准备阶段
    • 1.一个能在公网上访问的项目:
      • 2.一个微信公众平台账号: 
        • 3.策略文件
          • 4.微信官方消息加解密工具包
          • 二、填写服务器配置
            • 1.记住 AppID 和 AppSecret
              • 2.设置IP白名单
                • 3.填写服务器配置
                  • 3.1 URL:
                    • 3.2 Token:
                      • 3.3 EncodingAESKey:
                        • 3.4 消息加解密方式
                        • 三、验证服务器地址的有效性
                          • 1. 设置失败
                            • 2.签名校验的流程
                              • 3.微信服务器怎么判断签名校验是否成功?
                                • 4.签名校验的代码实现
                                  • 4.1  用SHA1算法生成安全签名 signature1
                                  • 4.2 验证signature1是否与signature相同
                                  • 4.3 在servlet的doGet方法中进行url的校验
                              •  四、代码实现
                                • 1.微信配置类—Env.java
                                  • 2.HTTP请求工具类—HttpHelper.java
                                    • 3.Token相关工具类—AuthHelper.java
                                      • 4.验证URL的servlet—WeiXinServlet
                                        • 5.微信公众号SHA1加密算法工具类—SHA1.java
                                          • 6.校验url—WXBizMsgCrypt.java
                                          相关产品与服务
                                          弹性公网 IP
                                          弹性公网 IP(Elastic IP,EIP)是可以独立购买和持有,且在某个地域下固定不变的公网 IP 地址,可以与 CVM、NAT 网关、弹性网卡和高可用虚拟 IP 等云资源绑定,提供访问公网和被公网访问能力;还可与云资源的生命周期解耦合,单独进行操作;同时提供多种计费模式,您可以根据业务特点灵活选择,以降低公网成本。
                                          领券
                                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档