packagecom.ray.weixin.gz.util;importjava.io.UnsupportedEncodingException;importjava.net.URLDecoder;importjava.security.MessageDigest;importjava.security.NoSuchAlgorithmException;importjava.util.Arrays;importjava.util.Formatter;importjava.util.UUID;importjavax.servlet.http.HttpServletRequest;importorg.apache.logging.log4j.LogManager;importorg.apache.logging.log4j.Logger;importcom.alibaba.fastjson.JSONObject;importcom.ray.weixin.gz.config.Env;importcom.ray.weixin.gz.service.invoice.InvoiceService;/*** 微信公众号 Token、配置工具类
* @desc : AccessToken、Jsticket 、Jsapi
*
*@author: shirayner
* @date : 2017年9月27日 下午5:00:25*/
public classAuthHelper {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
*
*@paramappId 第三方用户唯一凭证
*@paramappSecret 第三方用户唯一凭证密钥,即appsecret
*
*@return* access_token 获取到的凭证
* expires_in 凭证有效时间,单位:秒
*@throwsException String*/
public static String getAccessToken(String appId,String appSecret) throwsException {//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");
}
}returnaccessToken;
}/*** @desc :2.获取JsapiTicket
*
*@paramaccessToken 有效凭证
*@return*@throwsException String*/
public static String getJsapiTicket(String accessToken) throwsException {//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");
}
}returnjsapiTicket;
}/*** @desc : 3.通过code换取网页授权access_token
*
*@paramappId 第三方用户唯一凭证
*@paramappSecret 第三方用户唯一凭证密钥,即appsecret
*@paramCode code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
*
*@return* access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
* expires_in access_token接口调用凭证超时时间,单位(秒)
* refresh_token 用户刷新access_token
* openid 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
* scope 用户授权的作用域,使用逗号(,)分隔
*
*@throwsException String*/
public static JSONObject getAccessTokenByCode(String appId,String appSecret,String code) throwsException {//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;
}
}returnreturnJsonObject;
}/*** @desc :4.获取前端jsapi需要的配置参数
*
*@paramrequest
*@returnString*/
public staticString 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);returnconfigValue;
}/*** @desc : 4.1 生成签名的函数
*
*@paramticket jsticket
*@paramnonceStr 随机串,自己定义
*@paramtimeStamp 生成签名用的时间戳
*@paramurl 需要进行免登鉴权的页面地址,也就是执行dd.config的页面地址
*@return*@throwsException String*/
public static String getSign(String jsTicket, String nonceStr, Long timeStamp, String url) throwsException {
String plainTex= "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "×tamp=" + timeStamp + "&url=" +url;
System.out.println(plainTex);try{
MessageDigest crypt= MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(plainTex.getBytes("UTF-8"));returnbyteToHex(crypt.digest());
}catch(NoSuchAlgorithmException e) {throw newException(e.getMessage());
}catch(UnsupportedEncodingException e) {throw newException(e.getMessage());
}
}/*** @desc :4.2 将bytes类型的数据转化为16进制类型
*
*@paramhash
*@return* String*/
private static String byteToHex(byte[] hash) {
Formatter formatter= newFormatter();for (byteb : hash) {
formatter.format("%02x", newObject[] { Byte.valueOf(b) });
}
String result=formatter.toString();
formatter.close();returnresult;
}/**5.获取前端所需发票签名参数
*
* @desc :
*(1)将 api_ticket、appid、timestamp、nonceStr、cardType的value值进行字符串的字典序排序。
*(2)再将所有参数字符串拼接成一个字符串进行sha1加密,得到cardSign。
*
*@returnString
* timestamp :卡券签名时间戳
nonceStr : 卡券签名随机串
signType : 签名方式,默认'SHA1'
cardSign : 卡券签名
**/
public staticString getInvoiceConfig(){//1.准备好签名参数//1.1 api_ticket 授权页ticket
String apiTicket=null;try{
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
apiTicket=InvoiceService.getAuthPageTicket(accessToken);
}catch(Exception e) {
logger.info("获取授权页ticket失败");
e.printStackTrace();
}//1.2 appid
String appId=Env.APP_ID;//1.3 timestamp 时间戳
String timeStamp = System.currentTimeMillis() / 1000 +"";//1.4 nonceStr 随机数
String nonceStr=UUID.randomUUID().toString();//1.5 cardType
String cardType="INVOICE";//2.获取签名
String cardSign=null;try{
cardSign=AuthHelper.getCardSign(apiTicket, appId, timeStamp, nonceStr, cardType);
}catch(Exception e) {
logger.info("获取发票签名失败");
e.printStackTrace();
}
String signType="SHA1";
logger.info("apiTicket:"+apiTicket);
logger.info("appId:"+appId);
logger.info("timeStamp:"+timeStamp);
logger.info("nonceStr:"+nonceStr);
logger.info("cardType:"+cardType);
logger.info("cardSign:"+cardSign);
logger.info("signType:"+signType);//3.返回前端所需发票签名参数
JSONObject jsonObject=newJSONObject();
jsonObject.put("timestamp", timeStamp);
jsonObject.put("nonceStr",nonceStr );
jsonObject.put("signType",signType );
jsonObject.put("cardSign", cardSign);
String configValue=jsonObject.toJSONString();
logger.info("configValue:"+configValue);returnconfigValue;
}/*** @desc :5.1获取发票签名
*
*@paramapiTicket 授权页ticket,见InvoiceService
*@paramappId
*@paramtimeStamp 时间戳
*@paramnonceStr 随机串
*@paramcardType 填入INVOICE
*@return*@throwsException
* String*/
public static String getCardSign(String apiTicket, String appId, String timeStamp, String nonceStr,String cardType) throwsException {//1.将 api_ticket、appid、timestamp、nonceStr、cardType的value值进行字符串的字典序排序。//注意:是value值值
String[] array = newString[] { apiTicket, appId, timeStamp, nonceStr,cardType};
StringBuffer sb= newStringBuffer();//字符串排序
Arrays.sort(array);for (int i = 0; i < 5; i++) {
sb.append(array[i]);
}
String plainTex=sb.toString();//String plainTex = apiTicket+appId+cardType+nonceStr+timeStamp;
System.out.println("plainTex:"+plainTex);try{
MessageDigest crypt= MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(plainTex.getBytes("UTF-8"));returnbyteToHex(crypt.digest());
}catch(NoSuchAlgorithmException e) {throw newException(e.getMessage());
}catch(UnsupportedEncodingException e) {throw newException(e.getMessage());
}
}public static String getSHA1(String apiTicket, String appId, String timeStamp, String nonceStr,String cardType) throwsException{
System.out.println("getSHA1-----------");try{
String[] array= newString[] { apiTicket, appId, timeStamp, nonceStr,cardType};
StringBuffer sb= newStringBuffer();//字符串排序
Arrays.sort(array);for (int i = 0; i < 5; i++) {
sb.append(array[i]);
}
String str=sb.toString();
logger.info("str:"+str);//SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());byte[] digest =md.digest();
StringBuffer hexstr= newStringBuffer();
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);
}returnhexstr.toString();
}catch(Exception e) {
e.printStackTrace();throw new Exception("获取发票签名失败");
}
}
}