最近公司需要进行微信公众号开发,要求微信用户点进公众号直接登录,在实现此功能的过程中,遇见了一些坑,写出来记在这里
具体文档信息如下两个链接,openId是获取unionId的前提
获取用户openId及unionId:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
根据openId获取用户unionId:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140839
经过梳理发现,同一个公司如果拥有不同的公众号、小程序….,同一个微信用户相对于这些公众号、小程序….的openId都是不同的,
此时需要我们申请一个微信开放平台账号,用这个微信开放平台账号把这些公众号、小程序….绑定起来
,同一个微信用户相对于同一个开放平台下的公众号、小程序…就有着完全相同的unionId了,这样可以实现,一个公司下的多公众号..之间的用户衔接。
微信开放平台:https://open.weixin.qq.com
在贴代码之前,把遇见的坑写在前面:
1. 使用如下链接获取unionId,在获取unionId时,报错:
{“errcode”:40001
,
“errmsg”:”invalid credential
,
access_token is invalid or not latest hint:
[
D_K0881vr49!
]
“}
官方文档如下:
注意这里的access_token其实是基础access_token。注意access_token需要做一下缓存,这里官方文档中有进行说明。我使用了redis进行缓存
获取基础access:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183
2. 如果使用如下链接进行unionId的获取,不要忘记,scope应为 snsapi_userInfo
3. 因为我使用了第一种方法,所以再说说第一种里面注意要点
(1)不要忘记把公众号绑定到开放平台,不然获取不到用户信息,包括unionId
(2)如果scope为
snsapi_base ,
一定要微信用户关注了此微信公众号,不然也获取不到unionId
(3)如果scope为
snsapi_userinfo
,那么用户授权允许之后,无论是否关注此微信公众号,都可以获取到unionId
贴代码:需要前端把code给我
public Result loginByOpenId(@RequestParam String code) {
String access_token;//token
String openId;//openid
String UnionID;//UnionID
Integer expires_in;//token 过期时间
//校验数据的合法性,是否为空
if (StringUtils.isBlank(code)) {
throw new ServiceException(MemberCodeConstant.USER_EMPTY);
}
//调用微信接口获取
RestTemplate restTemplate = new RestTemplate();
//获取openId
String httpOpenIdUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + fuwuAppid + "&secret=" + fuwuSecret + "&code=" + code + "&grant_type=authorization_code";
ResponseEntity<String> response = restTemplate.getForEntity(httpOpenIdUrl, String.class);
if (200 != response.getStatusCodeValue()) {
logger.error("请求失败,获取openId失败");
throw new ControllerException(MemberCodeConstant.ACCESS_TOKEN_GET_FAIL);
}
String r = response.getBody();
JSONObject body = JSONObject.parseObject(r);
if ((Integer) body.get("errcode") != null) {
logger.error("请求成功,但是获取openId失败,错误码:" + body.get("errcode"));
throw new ControllerException(MemberCodeConstant.ACCESS_TOKEN_GET_FAIL);
}
//网页授权token 不一定能用得上
//access_token = (String) body.get("access_token");
openId = (String) body.get("openid");
//获取基础access_token
try (Jedis jedis = jedisPool.getResource()) {
jedis.select(CommonConstant.REDIS_YANCODE);
access_token = jedis.get("access_token");
/** 不存在则重新去请求*/
if (StringUtils.isBlank(access_token)) {
//获取access_token
String httpTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + fuwuAppid + "&secret=" + fuwuSecret;
ResponseEntity<Map> response2 = restTemplate.getForEntity(httpTokenUrl, Map.class);
if (200 != response2.getStatusCodeValue()) {
logger.error("请求失败,获取access_token失败");
throw new ControllerException(MemberCodeConstant.ACCESS_TOKEN_GET_FAIL);
}
Map body2 = response2.getBody();
if ((Integer) body2.get("errcode") != null) {
logger.error("请求成功,但是获取access_token失败,错误码:" + body2.get("errcode"));
throw new ControllerException(MemberCodeConstant.ACCESS_TOKEN_GET_FAIL);
}
access_token = (String) body2.get("access_token");
expires_in = (Integer) body2.get("expires_in");
//把新的access_token放入redis缓存
jedis.set("access_token", access_token);
jedis.expire("access_token", expires_in);
}
}
//获取unionId
String httpUnionIDUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + access_token + "&openid=" + openId + "&lang=zh_CN";
ResponseEntity<String> response1 = restTemplate.getForEntity(httpUnionIDUrl, String.class);
if (200 != response1.getStatusCodeValue()) {
logger.error("请求失败,获取UnionId失败");
throw new ControllerException(MemberCodeConstant.ACCESS_TOKEN_GET_FAIL);
}
String s = response1.getBody();
JSONObject body1 = JSONObject.parseObject(s);
if ((Integer) body1.get("errcode") != null) {
logger.error("请求成功,但是获取UnionId失败,错误码:" + body1.get("errcode"));
throw new ControllerException(MemberCodeConstant.ACCESS_TOKEN_GET_FAIL);
}
UnionID = (String) body1.get("unionid");
//返回前端数据
HashMap<String, Object> map = new HashMap<>();
map.put("UnionID", UnionID);
return ResultGenerator.genSuccessResult(map);
}