获取微信认证服务号openid
官方文档
代码
通过code换取网页授权access_token
// 第二步:通过code换取网页授权access_token(网页授权token)
@RequestMapping("/getAccessToken")
public String getAccessToken(@RequestParam("code") String code, @RequestParam("openid") String openid) {
RestResponse<WechatResult> resultRestResponse = new RestResponse<>();
WechatResult result = new WechatResult();
logger.info("请求参数:openid===>" + openid + ",code===>" + code);
if (StringUtils.isBlank(code)) {
resultRestResponse.setResMessage("code不能为空===>" + code);
resultRestResponse.setRespCode(ErrorCode.INVALID_PARAMATER_ERROR);
resultRestResponse.setData(result);
return gson.toJson(resultRestResponse);
}
// 从redis缓存中取
if (StringUtils.isNotBlank(openid) && redisTemplate.hasKey(openid)) {
logger.info("openid过期时间===>" + redisTemplate.getExpire(openid) * 1000 + "毫秒");
return redisTemplate.opsForValue().get(openid);
}
long millisecondNow = System.currentTimeMillis();
// 获取网页授权token、openid
String reqUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
reqUrl = reqUrl.replace("APPID", wechatAccountConfig.getAppid())
.replace("SECRET", wechatAccountConfig.getSecret()).replace("CODE", code);
String info = HttpsUtils.httpsRequest(reqUrl, "GET", null);
logger.info("第二步:通过code获取openid,返回报文===>" + info);
AuthorizationTokenDTO auToken = gson.fromJson(info, AuthorizationTokenDTO.class);
if (auToken != null && StringUtils.isNotBlank(auToken.getOpenid())) {
result.setOpenid(auToken.getOpenid());
result.setAccessToken(auToken.getAccess_token());
} else {
resultRestResponse.setResMessage("获取openid===>" + info);
resultRestResponse.setRespCode(ErrorCode.SERVER_ERROR);
resultRestResponse.setData(result);
return gson.toJson(resultRestResponse);
}
// 多減去5秒
long millisecond = 7200000 - (System.currentTimeMillis() - millisecondNow) - 5000;
resultRestResponse.setRespCode(RestResponse.SUCCESS_CODE);
resultRestResponse.setData(result);
resultRestResponse.setResMessage("请求成功");
// 放入redis中,key为openid
redisTemplate.opsForValue().set(result.getOpenid(), gson.toJson(resultRestResponse), millisecond,
TimeUnit.MILLISECONDS);
logger.info("放入redis成功,openid过期时间===>" + millisecond + "毫秒" + ",放入信息===>" + gson.toJson(resultRestResponse));
return gson.toJson(resultRestResponse);
}
获取基础token
@RequestMapping("/getBasicToken")
public String getBasicToken() {
return basicToken();
}
private String basicToken() {
// 从redis缓存中取
if (redisTemplate.hasKey(WX_BASIC_ACCESS_TOKEN)) {
logger.info("WX_BASIC_ACCESS_TOKEN过期时间===>" + redisTemplate.getExpire(WX_BASIC_ACCESS_TOKEN) * 1000 + "毫秒");
return redisTemplate.opsForValue().get(WX_BASIC_ACCESS_TOKEN);
}
long millisecondNow = System.currentTimeMillis();
// 获取基础token(GET) 限200(次/天)
String reqUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
reqUrl = reqUrl.replace("APPID", wechatAccountConfig.getAppid()).replace("APPSECRET",
wechatAccountConfig.getSecret());
String info = HttpsUtils.httpsRequest(reqUrl, "GET", null);
logger.info("获取基础token,返回报文===>" + info);
BasicTokenDTO token = gson.fromJson(info, BasicTokenDTO.class);
String accessToken = "";
if (token != null && token.getAccess_token() != null) {
accessToken = token.getAccess_token();
}
// 访问超时,或者访问出错,accessToken为空时,不放入redis中
if (StringUtils.isEmpty(accessToken)) {
return accessToken;
}
// 多減去5秒
long millisecond = 7200000 - (System.currentTimeMillis() - millisecondNow) - 5000;
// 放入redis中,key为WX_BASIC_ACCESS_TOKEN
redisTemplate.opsForValue().set(WX_BASIC_ACCESS_TOKEN, accessToken, millisecond, TimeUnit.MILLISECONDS);
logger.info("放入redis成功,WX_BASIC_ACCESS_TOKEN过期时间===>" + millisecond + "毫秒" + ",accessToken===>" + accessToken);
return accessToken;
}
刷新access_token
// 第三步:刷新access_token(如果需要)
@RequestMapping("/getRefreshToken")
public String getRefreshToken(@RequestParam("refreshToken") String refreshToken) {
String reqUrl = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";
reqUrl = reqUrl.replace("APPID", wechatAccountConfig.getAppid()).replace("REFRESH_TOKEN", refreshToken);
String info = HttpsUtils.httpsRequest(reqUrl, "GET", null);
logger.info("第三步:刷新access_token,返回报文===>" + info);
return info;
}
拉取用户信息
// 第四步:拉取用户信息(需scope为 snsapi_userinfo)
@RequestMapping("/getUserInfo")
public String getUserInfo(@RequestParam("accessToken") String accessToken, @RequestParam("openId") String openId) {
String reqUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
reqUrl = reqUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
String info = HttpsUtils.httpsRequest(reqUrl, "GET", null);
return info;
}
生成授权链接
// 生成授权链接
@RequestMapping("/getAuthorizationLink")
public String getAuthorizationLink(@RequestParam("menuUrl") String menuUrl, @RequestParam("state") String state) {
// 生成授权链接
String authorizationLink = wxMpService.oauth2buildAuthorizationUrl(menuUrl,
WxConsts.OAuth2Scope.SNSAPI_USERINFO, state);
logger.info("生成授权链接===>" + authorizationLink);
return authorizationLink;
}
发送模板消息
// 发送模板消息
// https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277
@RequestMapping("/sendTemplateMsg")
public String sendTemplateMsg(@RequestParam("data") String data) {
String reqUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
reqUrl = reqUrl.replace("ACCESS_TOKEN", getBasicToken());
String info = HttpsUtils.httpsRequest(reqUrl, "POST", data);
logger.info("发送模板消息接口,返回报文===>" + info);
return info;
}
获取JS-SDK使用权限签名
官方文档
代码
获取JS-SDK使用权限签名
// 获取JS-SDK使用权限签名
// pageUrl:当前网页的URL,不包含#及其后面部分(例如:http://sto.natapp1.dd/index.html?code=061uUcfq1yKgkj0frceq1gi7fq1uUcfQ&state=123456)
@RequestMapping("/getSignature")
public String getSignature(@RequestParam("pageUrl") String pageUrl) {
RestResponse<WechatResult> resultRestResponse = new RestResponse<>();
WechatResult result = new WechatResult();
logger.info("请求参数:pageUrl===>" + pageUrl);
if (StringUtils.isBlank(pageUrl)) {
resultRestResponse.setResMessage("pageUrl不能为空===>" + pageUrl);
resultRestResponse.setRespCode(ErrorCode.INVALID_PARAMATER_ERROR);
resultRestResponse.setData(result);
return gson.toJson(resultRestResponse);
}
// 定义ticket变量
String ticket = "";
// 从redis缓存中取
if (redisTemplate.hasKey(JSAPI_TICKET)) {
logger.info("JSAPI_TICKET过期时间===>" + redisTemplate.getExpire(JSAPI_TICKET) * 1000 + "毫秒");
ticket = redisTemplate.opsForValue().get(JSAPI_TICKET);
}
long millisecondNow = System.currentTimeMillis();
// 采用http GET方式请求获得jsapi_ticket
String reqUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
reqUrl = reqUrl.replace("ACCESS_TOKEN", basicToken());
String info = HttpsUtils.httpsRequest(reqUrl, "GET", null);
logger.info("获取jsapi_ticket,返回报文===>" + info);
TicketDTO dto = gson.fromJson(info, TicketDTO.class);
if (dto != null && StringUtils.isNotBlank(dto.getTicket())) {
ticket = dto.getTicket();
result.setTicket(ticket);
// 多減去5秒
long millisecond = 7200000 - (System.currentTimeMillis() - millisecondNow) - 5000;
if (StringUtils.isNotBlank(ticket)) {
// 放入redis中,key为JSAPI_TICKET
redisTemplate.opsForValue().set(JSAPI_TICKET, ticket, millisecond, TimeUnit.MILLISECONDS);
}
} else {
resultRestResponse.setResMessage("获取jsapi_ticket===>" + info);
resultRestResponse.setRespCode(ErrorCode.SERVER_ERROR);
resultRestResponse.setData(result);
return gson.toJson(resultRestResponse);
}
// 时间戳和随机字符串
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String noncestr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
// 将参数排序并拼接字符串
String str = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "×tamp=" + timestamp + "&url=" + pageUrl;
// 将字符串进行sha1加密
String signature = WechatUtil.SHA1(str);
logger.info("参数===>" + str + ",签名===>" + signature);
result.setTimestamp(timestamp);
result.setNoncestr(noncestr);
result.setSignature(signature);
result.setAppId(wechatAccountConfig.getAppid());
resultRestResponse.setRespCode(RestResponse.SUCCESS_CODE);
resultRestResponse.setData(result);
resultRestResponse.setResMessage("请求成功");
logger.info("获取签名成功,返回信息===>" + gson.toJson(resultRestResponse));
return gson.toJson(resultRestResponse);
}
工具类
代码
HttpsUtils
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
/**
* @author thebigdipperbdx
* @description ${todo}
* @date 2019-03-28 9:47
*/
public class HttpsUtils {
private static Logger logger = Logger.getLogger(HttpsUtils.class);
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
// 初始化一个json对象
String result = "";
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tmManagers = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tmManagers, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory sslSocket = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
httpsURLConnection.setSSLSocketFactory(sslSocket);
//设置超时时间为10秒
httpsURLConnection.setConnectTimeout(10000);
httpsURLConnection.setReadTimeout(10000);
httpsURLConnection.setDoOutput(true);
httpsURLConnection.setDoInput(true);
httpsURLConnection.setUseCaches(false);
// 设置请求方式 GET/POST
httpsURLConnection.setRequestMethod(requestMethod);
// 不考虑大小写。如果两个字符串的长度相等,并且两个字符串中的相应字符都相等(忽略大小写),则认为这两个字符串是相等的。
if ("GET".equalsIgnoreCase(requestMethod)) {
httpsURLConnection.connect();
}
// 当有数据需要提交时,往服务器端写内容 也就是发起http请求需要带的参数
if (StringUtils.isNotEmpty(outputStr)) {
OutputStream outputStream = httpsURLConnection.getOutputStream();
// 注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 获得输入流 读取服务器端返回的内容
InputStream inputStream = httpsURLConnection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer stringBuffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
stringBuffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
httpsURLConnection.disconnect();
// 将字符串转换为json对象
result = stringBuffer.toString();
} catch (ConnectException ce) {
logger.error("Weixin server connection timed out.");
} catch (Exception e) {
logger.error("https request error:{}", e);
}
return result;
}
}
MyX509TrustManager
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
/**
* @author thebigdipperbdx
* @description ${todo}
* @date 2019-03-28 9:50
*/
public class MyX509TrustManager implements X509TrustManager {
/**
* 该方法用于检查客户端的证书,若不信则抛出异常
* 由于我们不需要对客户端进行认证,可以不做任何处理
*/
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateEncodingException{
}
/**
* 该方法用于检验服务器端的证书,若不信任则抛出异常
* 通过自己实现该方法,可以使之信任我们指定的任何证书
* 在实现该方法时,也可以不做任何处理,即一个空的方法实现
* 由于不会抛出异常,它就会信任任何证书
*/
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateEncodingException{
}
/**
* 返回收信任的X509证书数组
*/
@Override
public X509Certificate[] getAcceptedIssuers(){
return null;
}
}
WechatMpConfig
import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* @author thebigdipperbdx
* @description
* 参考文档:
* 1、https://blog.csdn.net/qq_35164810/article/details/78710417
* @date 2019-03-27 14:01
*/
@Component
public class WechatMpConfig {
@Autowired
private WechatAccountConfig wechatAccountConfig;
// 首先将appid和secret放进一个WxMpService,创建一个WxMpService对象
// 此注解指定在Spring容器启动时,就执行该方法并将该方法返回的对象交由Spring容器管理
@Bean
public WxMpService wxMpService(){
//创建WxMpService实例并设置appid和sectret
WxMpService wxMpService=new WxMpServiceImpl();
// 设置配置信息的存储位置
wxMpService.setWxMpConfigStorage(wxConfigProvider());
return wxMpService;
}
@Bean
public WxMpConfigStorage wxConfigProvider(){
WxMpInMemoryConfigStorage wxConfigProvider=new WxMpInMemoryConfigStorage();
wxConfigProvider.setAppId(wechatAccountConfig.getAppid());
wxConfigProvider.setSecret(wechatAccountConfig.getSecret());
return wxConfigProvider;
}
}