package com.hy.utils.wechat;
import com.hy.common.redis.RedisPublicManager;
import com.hy.common.utils.Constant;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
/**
* 微信开发相关工具
*
*/
public class WechatUtils {
private static Logger log = LoggerFactory.getLogger(WechatUtils.class);
private static final String jsApi_Url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
//普通access_token_url
private static final String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
//通过普通access_token获取公众号关注者个人信息
private static final String token_userinfo_url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
//授权code_url
private static final String oauth_code_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
//授权access_token_url
private static final String oauth_access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
//根据授权access_token获取用户信息
private static final String oauth_token_userinfo_url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
/**
* 获取微信授权access_token
* @param appId
* @param appsecret
* @param code
* @return
* @throws Exception
*/
public static com.alibaba.fastjson.JSONObject getWxOauthToken(String appId,String appsecret,String code) throws Exception {
String url= oauth_access_token_url.replace("APPID",appId).replace("SECRET", appsecret).replace("CODE", code);
String result = httpRequest(url,"GET",null);
com.alibaba.fastjson.JSONObject jsonresult = com.alibaba.fastjson.JSONObject.parseObject(result);
log.info("oauth access_token:{} ", jsonresult);
return jsonresult;
}
/**
* 获取公众号关注者的个人信息
* @param appId
* @param appsecret
* @param code
* @return
* @throws Exception
*/
public static com.alibaba.fastjson.JSONObject getWxOfficialUserInfo(String officialAccessToken,String openid) throws Exception {
String url= token_userinfo_url.replace("ACCESS_TOKEN",officialAccessToken).replace("OPENID", openid);
String result = httpRequest(url,"GET",null);
com.alibaba.fastjson.JSONObject jsonresult = com.alibaba.fastjson.JSONObject.parseObject(result);
log.info("official user info :{} ", jsonresult);
return jsonresult;
}
/**
* 根据授权access_token获取用户信息
* @param oauthAccessToken
* @param openid
* @return
* @throws Exception
*/
public static com.alibaba.fastjson.JSONObject getWxOauthUserInfo(String oauthAccessToken,String openid) throws Exception {
String url= oauth_token_userinfo_url.replace("ACCESS_TOKEN",oauthAccessToken).replace("OPENID", openid);
String result = httpRequest(url,"GET",null);
com.alibaba.fastjson.JSONObject jsonresult = com.alibaba.fastjson.JSONObject.parseObject(result);
log.info("oauth user info:{} ", jsonresult);
return jsonresult;
}
public static String getWxJsTicket(String appId,String appsecret) throws Exception {
String accessToken = RedisPublicManager.get(Constant.WECHAT_TOKEN_REDIS);
if(StringUtils.isEmpty(accessToken)) {
accessToken = getAccessToken(appId,appsecret);
}
String url= jsApi_Url.replace("ACCESS_TOKEN",accessToken);
String result = httpRequest(url,"GET",null);
JSONObject jsonresult = JSONObject.fromObject(result);
System.out.println("getWxJsTicket:="+jsonresult.toString());
String ticket = null;
if(jsonresult.getInt("errcode")==0) {
ticket = jsonresult.getString("ticket");
}
log.info("ticket jsapi_ticket:{} ", ticket);
return ticket;
}
public static String getAccessToken(String appId,String appSecret) {
AccessToken accessToken = null;
String requestUrl = access_token_url.replace("APPID", appId).replace("APPSECRET",appSecret);
JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
System.out.println("jsonObject:"+jsonObject);
// 如果请求成功
if (null != jsonObject) {
try {
accessToken = new AccessToken();
String token = jsonObject.getString("access_token");
accessToken.setToken(token);
accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
//设置缓存
RedisPublicManager.add(Constant.WECHAT_TOKEN_REDIS,token);
} catch (Exception e) {
accessToken = null;
e.printStackTrace();
// 获取token失败
log.info("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
return accessToken.getToken();
}
public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {
try {
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
//对浏览返回的对象进行重新编码
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
//读取对象
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
//用于存放读取对象结果的
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
//读取对象将结果读取出来
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
return buffer.toString();
} catch (ConnectException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return jsonObject;
}
public static String getJsapiSign(String noncestr,String jsapi_ticket,String timestamp,String url){
JSONObject jsonObject = new JSONObject();
jsonObject.put("jsapi_ticket",jsapi_ticket);
jsonObject.put("noncestr",noncestr);
jsonObject.put("timestamp",timestamp);
jsonObject.put("url",url);
jsonObject = sortJsonObject(jsonObject);
String body = "";
// 获取body信息拼接字符串
Iterator it = jsonObject.keys();
while(it.hasNext()){
String key = (String) it.next();
String value= jsonObject.getString(key);
body += "&"+key +"="+value;
}
body = body.substring(1);
System.out.println("body=====>"+body);
String signature = getSha1(body);
System.out.println("signature===>"+signature);
return signature;
}
public static JSONObject sortJsonObject(JSONObject obj) {
Map map = new TreeMap();
Iterator<String> it = obj.keys();
while (it.hasNext()) {
String key = it.next();
Object value = obj.get(key);
if (value instanceof JSONObject) {
map.put(key, sortJsonObject(JSONObject.fromObject(value)));
} else {
map.put(key, value);
}
}
return JSONObject.fromObject(map);
}
public static String getSha1(String str) {
if (str == null || str.length() == 0) {
return null;
}
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f'};
try {
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
mdTemp.update(str.getBytes("UTF-8"));
byte[] md = mdTemp.digest();
int j = md.length;
char buf[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
buf[k++] = hexDigits[byte0 & 0xf];
}
return new String(buf);
} catch (Exception e) {
return null;
}
}
public static Map<String, String> getSignature(String appId,String appsecret, String url) throws Exception {
String jsapiTicket = getWxJsTicket(appId, appsecret);
Map<String, String> ret = new HashMap<String, String>();
String nonceStr = createNonceStr();
String timestamp = createTimestamp();
String signature = "";
//注意这里参数名必须全部小写,且必须有序
String string1 = "jsapi_ticket=" + jsapiTicket +
"&noncestr=" + nonceStr +
"×tamp=" + timestamp +
"&url=" + url;
System.out.println(string1);
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ret.put("url", url);
ret.put("jsapiTicket", jsapiTicket);
ret.put("nonceStr", nonceStr);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
return ret;
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash){
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
private static String createNonceStr() {
return UUID.randomUUID().toString();
}
private static String createTimestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
调用:JSONObject result = WechatUtils.getWxOauthToken(Constant.appMobileId, Constant.appMobileSecret, code);
String officialAccessToken = WechatUtils.getAccessToken(Constant.appId, Constant.appsecret);
踩的坑:报错 errMsg config invalid signature
因为一开始是订阅号。用 wx-open-launch-weapp必须用服务号
得到服务号后。把域名添加上
点击js接口安全域名的设置后出现如下,把MP_verify_KuEMpGwqo3AMxFP2.txt下载下来,放到项目的根目录,放好后才能点击保存,如果放的目录正确那会弹出提交成功。
然后在浏览器里的url栏用域名/MP_verify_KuEMpGwqo3AMxFP2.txt 能正常访问就是成功了。
还要添加IP白名单。就是把测试正式环境的ip添加到白名单,点击查看有修改的按钮。
还是报错 errMsg config invalid signature
看的测试环境的日志发现前端传的url有%号
处理一下。不要有% 正常显示就成功了。
微信公众号官网:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
扫描二维码关注公众号,回复:
13220516 查看本文章
生成的签 名和以下链接生成的一样就代表是对的
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign