SSM实现JSSDK

2019-04-15  本文已影响0人  东西汉

  最近有对接微信的JSSDK,大概流程如下,先获取全局access_token(注意:这里的access_token不同于网页授权,即获取用户openid的access_token),拿access_token去换jsapi_ticket,然后将jsapi_ticket生成签名signature,下面记录下流程以及附上代码,现贴现用

准备工作

1.设置获取access_token的IP白名单 设置获取access_token的IP白名单
2.设置js调用安全域名 设置js调用安全域名
3.nginx配置相关文件访问跳转,已配置好的或者会的可以跳过直接看代码

server {
   listen 80;
   server_name www.*******.com;
   location   /MP_verify_sCA2Kb5zEqFxZ6Yu.txt{
   root   /www/8080/webapps; #文件放置的目录
}

#user  nobody;
worker_processes  4;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /root/logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;        proxy_pass http://127.0.0.1:8080/;
            proxy_set_header   Host             $host:$server_port;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    server {
        listen       80;
        server_name  www.*******.com;
        location /MP_verify_sCA2Kb5zEqFxZ6Yu.txt{
            root /www/8080/webapps;      #文件放置的目录
        }
        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http:    //127.0.0.1:8080/;
            client_max_body_size    10m;
            proxy_set_header   Host             $host:$server_port;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    upstream php {
        server unix:/tmp/php-cgi.socket;
        server 127.0.0.1:9000;
    }
    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

开发代码

package com.shadmin.common.util;

import com.alibaba.fastjson.JSONObject;

import java.util.Date;
import java.util.Random;

public class WechatUtil {

    public static String app_id = "你的微信公众号AppId"; //微信公众号AppId

    public static String app_secrect = "你的微信公众号AppSecrect"; //微信公众号AppSecrect

    private static String access_token; //微信获取的AccessToken_

    private static long token_expire_time;  //微信AccessToken的失效时间

    private static String jsapi_ticket; //微信前端调用JSSDK的凭证

    private static long jsapi_expire_time;    //JSSDK凭证的失效时间

    private static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    private static String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";

    /**
     * 用第一步拿到的access_token
     * https请求方式: GET
     * https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
     * grant_type   获取access_token填写client_credential
     * appid        第三方用户唯一凭证
     * secret       第三方用户唯一凭证密钥,即appsecret
     * 返回值  {"access_token":"ACCESS_TOKEN","expires_in":7200}
     */

    private static void getAccessToken(){
        if(new Date().getTime()/1000 > token_expire_time){
            //access_token已过期
            String requestUrl = access_token_url.replace("APPID", app_id).replace("APPSECRET", app_secrect);
            JSONObject jsonObject = HttpUtil.doGet(requestUrl);
            access_token = jsonObject.getString("access_token");
            if(access_token != null){
                token_expire_time = new Date().getTime()/1000 +7000;
            }

        }
    }


    /**
     * 第二步,用access_token换取jsapi_ticket
     * 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):
     * https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
     * {
     * "errcode":0,
     * "errmsg":"ok",
     * "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
     * "expires_in":7200
     * }
     */
    private static void getJsapiTicket(){
        if(new Date().getTime()/1000>jsapi_expire_time){
            //先更新基础access_token
            getAccessToken();
            //jsapi_token已过期
            String requestUrl = jsapi_ticket_url.replace("ACCESS_TOKEN", access_token);
            JSONObject res = HttpUtil.doGet(requestUrl);
            jsapi_ticket = res.getString("ticket");
            if (jsapi_ticket != null) {
                jsapi_expire_time = new Date().getTime() / 1000;
            }
        }
    }

    /**
     * 第三步,拿jsapi_ticket完成签名算法
     * 步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,
     * 使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
     * jsapi_ticket=sM4AOVd&noncestr=Wm3WZYTPz0wzccnW&timestamp=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,当前网页的URL,不包含#及其后面部分。
     * 3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
     */
    public static JSONObject getSignPackage(String page_url){
        //先更新jsapi_ticket
        getJsapiTicket();
        long timestamp = new Date().getTime() / 1000;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("appId", app_id);    //公众号唯一标识
        jsonObject.put("timestamp",timestamp);   //生成签名的时间戳
        String noncestr = getRandomString(16);
        jsonObject.put("nonceStr", noncestr);  //生成签名的随机串
        String shaStr = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + page_url;
        System.out.println(shaStr);
        String signature = SHA1.encode(shaStr);
        jsonObject.put("signature", signature); //签名
        jsonObject.put("jsapi_ticket", jsapi_ticket);
        return jsonObject;
    }

    /**
     * 获取随机串
     * @return
     */
    public static String getRandomString(int length){
        //定义一个字符串(A-Z,a-z,0-9)即62位;
        String str="zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
        //由Random生成随机数
        Random random=new Random();
        StringBuffer sb=new StringBuffer();
        //长度为几就循环几次
        for(int i=0; i<length; ++i){
            //产生0-61的数字
            int number=random.nextInt(62);
            //将产生的数字通过length次承载到sb中
            sb.append(str.charAt(number));
        }
        //将承载的字符转换成字符串
        return sb.toString();
    }


}

以下附上发送HTTP的get请求的函数

package com.shadmin.common.util;

import com.alibaba.fastjson.JSON;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import java.io.IOException;

public class HttpUtil {

    private static Logger logger = Logger.getLogger(HttpUtil.class);
    //get请求
    public static com.alibaba.fastjson.JSONObject doGet(String requestUrl) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String responseContent  = null;
        com.alibaba.fastjson.JSONObject result = null;
        try {
            //创建Get请求,
            HttpGet httpGet = new HttpGet(requestUrl);
            //执行Get请求,
            response = httpClient.execute(httpGet);
            //得到响应体
            HttpEntity entity = response.getEntity();
            //获取响应内容
            responseContent  = EntityUtils.toString(entity,"UTF-8");
            //转换为map
            result = JSON.parseObject(responseContent);
        } catch (IOException e) {
            logger.error("HttpUtil=====Start");
            logger.error(e.getMessage(),e);
            logger.error("HttpUtil=====End");
        }
        return result;
    }
}

然后给前端开一个接口,参数传当前页面的url就行

    /**
     * 获取微信JSSDK的签名
     * @param pageUrl 当前网页的URL,不包含#及其后面部分
     */
    @RequestMapping("getWechatSignature.htm")
    public @ResponseBody JSONObject getWechatSignature(HttpServletRequest request){
        String pageUrl = request.getParameter("pageUrl");
        JSONObject jsonObject = WechatUtil.getSignPackage(pageUrl);
        return jsonObject;
    }

前端调用时时相关代码

var url = location.href.split('#')[0]

$.ajax({
    url: 'http://localhost:8080/api/getWechatSignature.htm?pageUrl=' + url,
    headers: {
        'Content-Type': 'application/json;charset=utf8'
    },
    async: false,
    timeout: 20000
}).done(function (info) {
    info = JSON.parse(info);
    //console.table(info);
    //微信初始化权限验证
    wx.config({
        debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId: info.appId, // 必填,公众号的唯一标识
        timestamp: info.timestamp, // 必填,生成签名的时间戳
        nonceStr: info.nonceStr, // 必填,生成签名的随机串
        signature: info.signature, // 必填,签名,见附录1
        jsApiList: ['openAddress'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
    });
    //微信加载完
    wx.ready(function () {
        $('.addAddress').on('click', function () {
            wx.openAddress({
                success: function (res) {
                    // 用户成功拉出地址 
                },
                cancel: function () {
                    // 用户取消拉出地址
                },
                error:function (res) {
                    console.log(res)
                }
            });
        })
    });
    wx.error(function (res) {
        console.log(res)
    });

});

以下附上相关路径
微信公众平台首页
微信JS-SDK说明文档
微信 JS 接口签名校验工具

上一篇下一篇

猜你喜欢

热点阅读