对接微信第三方平台
首先本人是刚入职场的小菜鸟,因工作需要本次进行了对接微信第三方平台的项目开发。
项目主要实现任务:获取所有已授权小程序的昵称,授权时间和小程序的id
本文主要参考『做一个安静的美男子』,阿·成,人类电影精华丶的文章
首先将所需的url放入到一个常量类中
package com.xye.core.thirdpartyplug.constant;
public class WxPostUrlConstant {
private WxPostUrlConstant(){
}
/**
* 微信调用接口url
*/
public static final String API_COMPONENT_TOKEN_URl="https://api.weixin.qq.com/cgi-bin/component/api_component_token";
/*
* 预授权码url*/
public static final String API_CREATE_PREAUTHCODE_URL="https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=";
/*
* 获取授权信息url*/
public static final String API_QUERY_AUTH_URL="https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=";
/*
* 获取或刷新调用令牌url*/
public static final String API_AUTHORIZER_TOKEN_URL="https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=";
/*
* 获取授权方的帐号基本信息url*/
public static final String API_GET_AUTHORIZER_INFO_URL="https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=";
/*
* 设置授权方选项信息url*/
public static final String API_GET_AUTHORIZER_List="https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token=";
}
一、获取验证票据 component_verify_ticket
主要用到官方提供的解密加密的工具类
Controller类
@RestController
@RequestMapping("/wechatAuth")
@Slf4j
public class WeChatAuthController {
@Autowired
private WeChatAuthService weChatAuthService;
@PostMapping(path = "/parseRequest")
@ApiOperation(value = "获得授权事件的票据", httpMethod = "POST", notes = "获得授权事件的票据", code = 200)
public String parseRequest(HttpServletRequest request, HttpServletResponse response){
log.info("接收微信服务器发送的component_verify_ticket begin");
try {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
// 微信加密签名
String msgSignature = request.getParameter("msg_signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 从请求中读取整个post数据
InputStream inputStream;
String postData = null;
inputStream = request.getInputStream();
postData= IOUtils.toString(inputStream, "UTF-8"); //获取接收到消息里的XML密文,存放在postData中
log.info("postData:"+postData);
weChatAuthService.parseRequest (timestamp,nonce,msgSignature,postData);
} catch (Exception e) {
log.error("Exception",e);
}
return "success";
}
weChatAuthService
/**
* 获取票据
* @param timestamp
* @param nonce
* @param msgSignature
* @param postdata
* @return
*/
String parseRequest (String timestamp,String nonce,String msgSignature,String postdata);
weChatAuthServiceImpl
本项目的appId存放在数据库中,为了实现动态获取不同appId的信息,所以在配置文件中配置唯一标识mallCode进行实现
主要使用到的工具类是从『做一个安静的美男子』获取
@Slf4j
@Service
@Configuration
public class WeChatAuthServiceImpl implements WeChatAuthService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private AuthService authService;
@Value ( "${wx.mallCode}" )
private String mallCode;
/*
* 每隔10分钟推送一次,进行一次被迫接收*/
@Override
public String parseRequest (String timestamp,String nonce,String msgSignature,String postData){
log.info ( "开始授权事件接收URL--->入参{}:"+mallCode );
try {
//ThirdpartyInfo是一个实体类主要是将第三方平台appId、第三方平台 secret、第三方平台 消息加解密Key、第三方平台 消息校验Token从数据库中取出来
ThirdpartyInfo thirdpartyInfo=authService.queryAppId ( mallCode ).getData ();
String appId= thirdpartyInfo.getAppId ();
String appKey= thirdpartyInfo.getAppKey ();
String componentToken=thirdpartyInfo.getComponentToken ();
log.info ( "appId--->{}:"+appId );
// 这个类是微信官网提供的解密类,需要用到消息校验Token 消息加密Key和服务平台appid
WXBizMsgCrypt pc = new WXBizMsgCrypt(componentToken, appKey, appId);
String xml = pc.decryptMsg(msgSignature,timestamp,nonce, postData);
// 将xml转为map
Map<String, String> result = WXXmlToMapUtil.xmlToMap(xml);
String infotype=MapUtils.getString ( result,"InfoType" );
log.info(infotype);
switch (infotype){
case "component_verify_ticket": //验证票据
String componentVerifyTicket = MapUtils.getString(result, "ComponentVerifyTicket");
if (StringUtils.isNotEmpty(componentVerifyTicket)) {
// 存储平台授权票据,保存ticket
redisTemplate.opsForValue ().set ( "component_verify_ticket", componentVerifyTicket, 60 * 60, TimeUnit.SECONDS );
String verifyTicket = redisTemplate.opsForValue ().get ( "component_verify_ticket" ).toString ();
log.info ( "授权票据ComponentVerifyTicket---->{}:" ,verifyTicket );
}
break;
case "unauthorized"://用户取消授权
log.info ( "用户取消授权" );
break;
case"updateauthorized"://用户更新授权
log.info("用户更新授权");
break;
case"authorized"://授权成功
log.info ( "授权成功" );
break;
}
} catch (Exception e) {
log.error(e.getMessage());
return "success";
}
log.info("==============================结束授权事件接收URL=================================");
return "success";
}
二、获取令牌
//2.获取令牌
@Override
public String getAccessToken(String mallCode) {//mallCode根据自己需求来,不是必须的
String accessToken = getCache("component_access_token");
if (accessToken != null) {
log.info("缓存获取令牌component_access_token");
return accessToken;
}
String componentVerifyTicket = getCache("component_verify_ticket");
// String componentVerifyTicket = redisTemplate.opsForValue().get("component_verify_ticket").toString();
log.info("获取到的票据--->{}:",componentVerifyTicket);
ThirdpartyInfo thirdpartyInfo=authService.queryAppId ( mallCode );
String appId=thirdpartyInfo.getAppId ();
String appSecret=thirdpartyInfo.getAppSecret ();
log.info ( "appSecret--->{}:",appSecret );
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", appId);
jsonObject.put("component_appsecret", appSecret);
jsonObject.put("component_verify_ticket", componentVerifyTicket);
String post = OKHttpUtil.post( WxPostUrlConstant.API_COMPONENT_TOKEN_URl, jsonObject, String.class);
log.info ("====================返回post结果:" + post);
HashMap<String, String> hashMap = JSON.parseObject(post, HashMap.class);
String componentAccessToken = hashMap.get("component_access_token");
Long expires=6600L;
if (StringUtils.isNotEmpty(componentAccessToken)) {
redisTemplate.opsForValue().set("component_access_token", componentAccessToken, expires, TimeUnit.SECONDS);
} else {
throw new RuntimeException("微信开放平台,第三方平台获取令牌失败");
}
return componentAccessToken;
}
三、获取预授权码
@Override
public String getPreAuthCode(String mallCode) {
try {
String preAuthCode = getCache("pre_auth_code");
if (preAuthCode != null) {
log.info("缓存获取pre_auth_code");
return preAuthCode;
}
String accessToken =getAccessToken (mallCode);
ThirdpartyInfo thirdpartyInfo=authService.queryAppId ( mallCode );
String appId=thirdpartyInfo.getAppId ();
log.info ( "appId---->{}:",appId );
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", appId);
String post = OKHttpUtil.post(WxPostUrlConstant.API_CREATE_PREAUTHCODE_URL + accessToken,jsonObject, String.class );
log.info ("====================返回post结果:" + post);
HashMap<String, String> hashMap = JSON.parseObject(post, HashMap.class);
String pAuthCode = hashMap.get("pre_auth_code");
if (StringUtils.isNotEmpty(pAuthCode)) {
redisTemplate.opsForValue().set("pre_auth_code", pAuthCode, 60 * 10, TimeUnit.SECONDS);
} else {
throw new RuntimeException("微信开放平台,第三方平台获取预授权码失败");
}
return pAuthCode;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
四、进行授权,获取授权页面
Controller
@PostMapping(path = "/queryUrl")
@ApiOperation(value = "授权地址", httpMethod = "POST", notes = "授权地址", code = 200)
public String authUrl(HttpServletRequest request) {
return authService.queryAuthUrl (mallCode);
}
AuthServiceImpl
@Service
@Slf4j
public class AuthServiceImpl implements AuthService {
@Autowired
private ThirdpartyInfoMapper mapper;
@Autowired
private WeChatAuthService weChatAuthService;
@Value("${wx.redirectUrl}")
private String wxRedirectUrl;
@Override
public String queryAuthUrl(String mallCode) {
log.info("获取授权url---->入参{}:",mallCode);
//获取预授权码
String preAuthCode =weChatAuthService.getPreAuthCode (mallCode);
//授权页网址
ThirdpartyInfo thirdpartyInfo=queryAppId ( mallCode ).getData ();
String appId=thirdpartyInfo.getAppId ();
try {
String redirectUrl = URLEncoder.encode(wxRedirectUrl, "utf-8");
log.info ( "=======redirectUrl===",redirectUrl );
String url = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=" + appId + "&pre_auth_code=" + preAuthCode + "&redirect_uri="+redirectUrl + "&auth_type=2";
return url;
} catch (Exception e) {
log.error("获取微信授权地址异常", e);
return "获取微信授权地址异常";
}
五、获取授权方的帐号基本信息
@Override
public String getAuthorizerInfo(String authorizerAppid,String mallCode ) {
log.info("获取授权方的帐号基本信息---->入参{}:",mallCode);
ThirdpartyInfo thirdpartyInfo=authService.queryAppId ( mallCode ).getData ();
String appId= thirdpartyInfo.getAppId ();
log.info ( "appId--->{}:",appId );
String accessToken=getAccessToken ( mallCode );
log.info ( "accessToken---->{}:",accessToken );
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", appId);
jsonObject.put("authorizer_appid",authorizerAppid);
String post = OKHttpUtil.post(WxPostUrlConstant.API_GET_AUTHORIZER_INFO_URL + accessToken,jsonObject, String.class);
log.info ("====================返回post结果:" + post);
JSONObject jsonObj=JSON.parseObject ( post );
JSONObject authorizerInfo=jsonObj.getJSONObject ( "authorizer_info" );
String nickName=authorizerInfo.getString ( "nick_name" );
log.info ( "nickName---->{}:",nickName );
return nickName;//因为只需要昵称所以返回了昵称
}
六、拉取所有已授权的帐号信息
@Override
public List<RespAuthorizerInfo> getAuthorizerAppid(String mallCode) {
log.info("获取所有已授权账号的id---->入参{}:",mallCode);
try {
ThirdpartyInfo thirdpartyInfo=authService.queryAppId ( mallCode );
String appId=thirdpartyInfo.getAppId ();
String accessToken=getAccessToken ( mallCode );
log.info ( "appId---->{}:",appId );
log.info ( "令牌--->{}:",accessToken );
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", appId);
jsonObject.put("offset", 0);
jsonObject.put("count",100);
String post = OKHttpUtil.post(WxPostUrlConstant.API_GET_AUTHORIZER_List + accessToken, jsonObject, String.class);
log.info ("====================返回post结果:" + post);
JSONObject jsonObj=JSON.parseObject ( post );
JSONArray jsonArray=jsonObj.getJSONArray ( "list" );
String jsonString=JSONObject.toJSONString (jsonArray);
List<AllTotalInfo> objectList=JSONObject.parseArray ( jsonString,AllTotalInfo.class );
List<RespAuthorizerInfo> respAuthorizerInfos=new ArrayList<> ();
SimpleDateFormat time=new SimpleDateFormat ( "yyyy-MM-dd HH:mm:ss" );
for (int i=0;i<objectList.size ();i++){
RespAuthorizerInfo respAuthorizerInfo=new RespAuthorizerInfo ();
AllTotalInfo allTotalInfo=objectList.get ( i );
String authorizerAppid=allTotalInfo.getAuthorizer_appid ();
int authTimeL=allTotalInfo.getAuth_time ();
String authTime=time.format ( new Date (authTimeL*1000L ) );
respAuthorizerInfo.setAuthTime (authTime);
respAuthorizerInfo.setAuthorizerAppid ( authorizerAppid );
respAuthorizerInfos.add ( respAuthorizerInfo );
}
log.info("获取到的所有已授权账号的id信息---->{}:",respAuthorizerInfos.toString ());
return respAuthorizerInfos;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected String getCache(String key) {
Object o = redisTemplate.opsForValue().get(key);
if (o == null) {
return null;
}
return o.toString();
}
七、获取所有已授权小程序的昵称,id,授权时间
@Override
public List<RespAuthorizerInfo> getAllAuthInfos(String mallCode){
List<RespAuthorizerInfo> respAuthorizerInfos=weChatAuthService.getAuthorizerAppid (mallCode);
List<RespAuthorizerInfo> respAuthorizerInfoList = new ArrayList<> ();
for (int i=0;i<respAuthorizerInfos.size ();i++){
String authorizerAppid=respAuthorizerInfos.get ( i ).getAuthorizerAppid ();
String authTime=respAuthorizerInfos.get ( i ).getAuthTime ();
String nickName=weChatAuthService.getAuthorizerInfo (authorizerAppid, mallCode );
RespAuthorizerInfo respAuthorizerInfo=new RespAuthorizerInfo ();
respAuthorizerInfo.setAuthorizerAppid ( authorizerAppid );
respAuthorizerInfo.setNickName ( nickName );
respAuthorizerInfo.setAuthTime ( authTime );
respAuthorizerInfoList.add ( respAuthorizerInfo );
}
return respAuthorizerInfoList;
}
其他模块目前没有使用到,但进行一个记录
八、使用授权码获取授权信息
Controller
@GetMapping(path = "/getAuthInfo")
@ApiOperation(value = "使用授权码获取授权信息", httpMethod = "GET", notes = "使用授权码获取授权信息", code = 200)
public AuthorizationInfo getAuthInfo(@RequestParam("auth_code")String authorizationCode, @RequestParam("expires_in")Long expiresIn, HttpServletRequest request) {
return weChatAuthService.getAuthInfo(authorizationCode,expiresIn);
}
WeChatAuthServiceImpl
//4.获取授权信息
@Override
public AuthorizationInfo getAuthInfo(String authorizationCode,Long expiresIn) {
redisTemplate.opsForValue ().set ("authorization_code",authorizationCode, expiresIn-4,TimeUnit.SECONDS );
ThirdpartyInfo thirdpartyInfo=authService.queryAppId ( mallCode );
String appId= thirdpartyInfo.getAppId ();
String accessToken = getAccessToken ( mallCode );
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", appId);
jsonObject.put ( "authorization_code",authorizationCode );
String post = OKHttpUtil.post(WxPostUrlConstant.API_QUERY_AUTH_URL + accessToken, jsonObject, String.class);
log.info ( "====================返回post结果:" + post);
Map<String,Object> map= MapConvertUtil.jsonToMap ( post );
ObjectMapper objectMapper=new ObjectMapper ();
AuthorizationInfo authorizationInfo=objectMapper.convertValue ( map.get("authorization_info"),AuthorizationInfo.class );
Long expires=authorizationInfo.getExpires_in ();
if (authorizationInfo!=null) {
redisTemplate.opsForValue().set("authorizer_refresh_token", authorizationInfo.getAuthorizer_refresh_token (),expires-4,TimeUnit.SECONDS);
return authorizationInfo;
} else {
throw new RuntimeException("微信开放平台,第三方平台获取授权信息失败");
}
}
九、获取/刷新接口调用令牌
//5.获取/刷新接口调用令牌
@Override
public String getAuthorizerAccessToken() {
try {
String authorizerAccessToken = getCache("authorizer_access_token");
if (authorizerAccessToken != null) {
log.info("缓存获取pre_auth_code");
return authorizerAccessToken;
}
String accessToken=getAccessToken ( mallCode );
String authorizerAppid= redisTemplate.opsForValue().get("authorizer_appid").toString();
String refreshToken= redisTemplate.opsForValue().get("authorizer_refresh_token").toString();
String appId= redisTemplate.opsForValue ().get ( "app_id").toString ();//没有使用上所以这样获取,可以修改
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", appId);
jsonObject.put("authorizer_appid", authorizerAppid);
jsonObject.put("authorizer_refresh_token", refreshToken);
String post = OKHttpUtil.post(WxPostUrlConstant.API_AUTHORIZER_TOKEN_URL + accessToken,jsonObject, String.class);
log.info ("====================返回post结果:" + post);
HashMap<String, String> hashMap = JSON.parseObject(post, HashMap.class);
String authAccessToken = hashMap.get("authorizer_access_token");
String authorizerRefreshToken = hashMap.get("authorizer_refresh_token");
if (StringUtils.isNoneEmpty ( authAccessToken,authorizerRefreshToken )) {
redisTemplate.opsForValue().set("authorizer_access_token", authAccessToken,7100,TimeUnit.SECONDS);
} else {
throw new RuntimeException("微信开放平台,第三方平台获取或刷新调用令牌失败");
}
return authAccessToken;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
十、有待验证,目前还存在问题
//7.获取授权方选项信息
/*
* 不太清楚option_name的来源
* 需要Controller
* */
@Scheduled(cron = "0 50 1/2 * * ?")
private void getOptionInfo() {
log.debug("====================开始执行定时任务获取授权方选项信息====================");
try {
String accessToken = redisTemplate.opsForValue().get("component_access_token").toString();
String authorizerAppid= redisTemplate.opsForValue().get("authorizer_appid").toString();
String appId= redisTemplate.opsForValue ().get ( "app_id").toString ();
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", appId);
jsonObject.put("authorizer_appid", authorizerAppid);//从4来
jsonObject.put("option_name", OptionNameEnum.LOCATION_REPORT.getMessage());//从哪来
String post = OKHttpUtil.post(WxPostUrlConstant.API_GET_AUTHORIZER_OPTION + accessToken, jsonObject, String.class);
log.debug("====================返回post结果:" + post);
HashMap<String, String> hashMap = JSON.parseObject(post, HashMap.class);
String authorizerAppidRet = hashMap.get("authorizer_appid");
String optionName = hashMap.get("option_name");
String optionValue = hashMap.get("option_value");
if (!hashMap.isEmpty ()) {
redisTemplate.opsForValue().set("authorizer_appid", authorizerAppidRet);
redisTemplate.opsForValue().set("option_name", optionName);
redisTemplate.opsForValue().set("option_value", optionValue);
} else {
throw new RuntimeException("微信开放平台,第三方平台获取授权方的帐号基本信息失败");
}
} catch (Exception e) {
e.printStackTrace();
}
log.debug("====================结束执行定时任务获取授权方选项信息====================");
}
//8.设置授权方选项信息
public String SetOptionInfo() {
try {
String accessToken = redisTemplate.opsForValue().get("component_access_token").toString();
String authorizerAppid= redisTemplate.opsForValue().get("authorizer_appid").toString();
String optionValue= redisTemplate.opsForValue().get("option_value").toString();
String appId= redisTemplate.opsForValue ().get ( "app_id").toString ();
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", appId);
jsonObject.put("authorizer_appid",authorizerAppid );//从4来
jsonObject.put("option_name", OptionNameEnum.LOCATION_REPORT.getMessage () );
jsonObject.put("option_value",optionValue);
String post = OKHttpUtil.post(WxPostUrlConstant.API_SET_AUTHORIZER_OPTION + accessToken, jsonObject, String.class);
log.debug("====================返回post结果:" + post);
HashMap<String, String> hashMap = JSON.parseObject(post, HashMap.class);
String errmsg = hashMap.get("errmsg");
if (!hashMap.isEmpty ()) {
if(errmsg=="ok"){
return "设置授权方选项信息成功";
}
} else {
throw new RuntimeException("微信开放平台,第三方平台获取授权方选项信息失败");
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
如果看到的小伙伴有什么好的建议可以告诉我哟,谢谢啦~