网上搜索了一下,还是有很多人问这个问题。但是,好些文章只讲了大概,对刚接触微信订阅号的人,依然比较懵!刚好最近也有一个场景需在做这个判断,我把这个过程整理出来。如果你刚好也在做类似的场景需求,可以参考一下。应该看了此篇文章,基本能解决你的问题。
说一下场景,一个朋友在自己的订阅号会经常发布一些马拉松的活动,他本身会被各种马拉松组织方邀请去拍照。所以会提供一些相片,供参加马拉松的人下载(在订阅号上发布链接)。他希望只有关注他订阅号的人才能访问相片的链接。
逻辑就是,如果用户访问链接,先判断用户是不是关注订阅号了,只有关注了就跳转到链接上去;如果没有关注,提标用户先关注(弹出个二维码)。需求就是这么简单。因为我之前没有做过这个判断,以为很简单。如果要判断用户有没有关注,首先要获取用户信息。
花了些时间研究了一下,发现订阅号无法做到。因为要获取用户信息,必须授权。但订阅号无法进行授权。只有服务号才能进行授权。所以第一版本就是重新注册了服务号。
服务号判断的实现
1. 先组织授权地址(包括redirect),成功后,微信会redirect过来,将code传回来。下一步获取access_token需要使用code
/**
*
* @param bizId 自己业务相关的参数,微信redirect时,再返回来
* @return
*/
public String authUrl(String bizId) {
String redirect = "";
try {
//配置redirect的 url
redirect = URLEncoder.encode(wechatConfig.getAuthRedirect(), "utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
//getApiAuth()为,微信提供的地址
return wechatConfig.getApiAuth()
.replace("APPID", wechatConfig.getAppid())//appId是必须的
.replace("REDIRECT_URI", redirect)
.replace("SCOPE", "snsapi_userinfo") //可根据需要,自行选择,参考微信官方文档
.replace("STATE", bizId);
}
2.获取access_token
@GetMapping("/auth")
@ResponseBody
public ApiResponse authCallBack(HttpServletRequest request) {
String code = request.getParameter("code");
String state = request.getParameter("state");
if (StringUtils.isEmpty(code)) {
return new ApiResponse().ofFailure(11, "code为空");
}
log.info("微信授权回调, code = {} ,state(race id) = {}", code, state);
try {
//获取微信授权access_token
final LocalAccessToken localAccessToken = weiXinService.getLocalAccessToken(code);
if (Objects.isNull(localAccessToken)) {
return new ApiResponse().ofFailure(11, "微信授权失败:");
}
log.info("微信授权access_token返回参数:{}", JSON.toJSONString(localAccessToken));
String accessToken = localAccessToken.getAccessToken();
String openId = localAccessToken.getOpenid();
String unionId = localAccessToken.getUnionId();
log.info("微信授权: " + "获取授权元数据:access token: {}, openid: {}, unionid: {}", accessToken, openId, unionId);
//如果微信的返回access_token为空
if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openId)) {
return new ApiResponse().ofFailure(11, "微信授权失败");
}
//这里是获取token见下面的代码说明,是为了获取用户是否订阅服务号的token
final AccessToken token = weiXinService.getUsersToken();
if (Objects.isNull(token)) {
log.error("#token# wrong");
return new ApiResponse().ofFailure(11, "微信授权失败");
}
String userInfoStr = httpClient.userInfoExt(token.getAccessToken(), openId, "zh_CN");
userInfoStr = new String(userInfoStr.getBytes("ISO-8859-1"), "UTF-8");
log.info("#微信授权# 用户信息 {}", userInfoStr);
if (userInfoStr.contains(ERR_CODE)) {
log.info("#微信授权# 用户信息 出错 {}", userInfoStr);
return new ApiResponse().ofFailure(11, "微信授权失败:" + userInfoStr);
}
WxUserInfo usr = JSON.parseObject(userInfoStr, WxUserInfo.class);
log.info("#微信授权# 用户信息 正常解析 {}", userInfoStr);
//为1,说明关注了;为0说明没有关注
boolean hasSub = usr.getSubscribe().intValue() == 1;
//下载逻辑省略
} catch (Exception e) {
log.info("#微信授权# 失败", e);
return new ApiResponse().ofFailure(11, "微信授权失败");
}
}
上面代码中“weiXinService.getUsersToken()”内部是调用此接口
/**
* access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。
* 开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。
* access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
* https://developers.weixin.qq.com/doc/offiaccount/WeChat_Invoice/Nontax_Bill/API_list.html#1.1
* @param grantType
* @param appid
* @return
*/
@RequestMapping(value = "https://api.weixin.qq.com/cgi-bin/token", method = RequestMethod.GET)
String getToken(@RequestParam("grant_type") String grantType,
@RequestParam("appid") String appid, @RequestParam("secret") String secret);
经过上面的2步,就可以判断出,用户是否关注服务号了。
订阅号怎么处理呢?
订阅号的判断,必须结合服务号一起实现,只是订阅号,无法判断出用户是否关注。其原理如下:
1.将订阅号绑定到服务号上。在一个服务号的不同应用,虽然openid不同,但unionid是一样的
2.通过微信提供的接口,将订阅号的用户同步到本地,比如mysql中。同步过来的数据只有openid。
3.通过调用接口查询出所有用户的unionid
4.订阅号配置服务。如果有用户订阅,取消订阅将信息推送给你的服务
5.用户通过服务号授权,可以获取到用户的unionid,拿关这个unionid去mysql查询,是否能查到。如果能查到说明已关注过了;如果查询不到,说明没有关注。
下一篇会写详细阐述实现方法。
本文如果哪里不清楚,可以留言交流!