很多人都觉得小程序用起来比较方便,并且小程序项目的运行速度要比嵌在公众号中的项目运行速度更快,刚好大家有这个需求,微信也有这个解决办法,大家都知道不管小程序还是公众号用户都有自己的唯一标识,那就是openID,但是其实用户还有一个标识就是unionId,这个标识的作用就是做关联的,小程序和公众号的用户是可以通过unionId来同步一些用户数据的,所以呢,具体做法如下:
要申请自己的一个微信开放平台,并且公众号和小程序要关联起来,这个关联很好配置,在微信公众平台进行配置就好了,同一个开放平台下的用户unionId都是相同的,一个开放平台下面可以添加多个微信的产品,比如我们公司一个微信开放平台下放了两个公众号两个小程序,就是说我们这四个产品相同用户的unionId是相同的。原理大概就是这样的,下面我就上代码了,怎么获取小程序用户和公众号用户的unionId,由于工作原因,公众号我是用java获取的,小程序我就用go语言获取的,但是只要原理懂了就简单了很多
@GetMapping(value = "/current/unionId") public Result unionId() { User user = (User) HttpContextUtils.getAttribute(SessionConstant.USER); if(StringUtils.isBlank(user.getUnionId())){ AccessToken accessToken = accessTokenService.currentToken(); RestTemplate restTemplate = new RestTemplate(); String httpUnionIDUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken.getAccessToken() + "&openid=" + user.getWeixinOpenId(); ResponseEntity<String> response1 = restTemplate.getForEntity(httpUnionIDUrl, String.class); if (200 != response1.getStatusCodeValue()) { LOGGER.error("请求失败,获取UnionId失败"); return Result.fail("请求失败,获取UnionId失败"); } String s = response1.getBody(); JSONObject body = JSONObject.fromObject(s); if ((Integer) body.get("errcode") != null) { LOGGER.error("请求成功,但是获取UnionId失败,错误码:" + body.get("errcode")); return Result.fail("请求成功,但是获取UnionId失败,错误码:" + body.get("errcode")); } String unionID = (String) body.get("unionid"); Integer num = userService.saveUnionId(user.getId(),unionID); } return Result.success(); }
获取公众号的unionId需要两样东西,accessToken和用户的openId。
我的代码里面已经把用户的数据存在了session中,我直接拿出来就用了,token的话是封装了一个获取数据库中token的service,直接调就好了。
func UserWXOpenId(w http.ResponseWriter, r *http.Request) { //配置请求头 w.Header().Set("Access-Control-Allow-Origin", "*") //连接数据库 db, err := sql.Open(common.StoreType, common.DataSourceName) methods.CheckErr(err) defer db.Close(); //获取code值 r.ParseForm() //用户访问时的code code := r.Form.Get("code") glog.Infof("code : ", code) //调用方法获取openID,unionId if openID, err := methods.WxOpenId(code); err != nil { fmt.Println(err) os.Exit(1) } else if openID.OpenId == "" { glog.Infof("无效的openid,openid为空") } else { glog.Infof("openID可用,存库并返回给前端session_key") open_id := openID.OpenId session_key := openID.Session_key union_id := openID.UnionId fmt.Println(open_id) fmt.Println(session_key) fmt.Println(union_id) } } func WxOpenId(code string) (openId *model.OpenID, err error) { //获取openID的URL var URL = common.BaseURL + "/sns/jscode2session?grant_type=authorization_code&appid=" + common.AppId + "&secret=" + common.AppSecret + "&js_code=" + code var _b []byte if response, err := http.Get(URL); err != nil { return openId, err } else { if _b, err = ioutil.ReadAll(response.Body); err != nil { return openId, err } } openId = &model.OpenID{} err = json.Unmarshal(_b, openId) // JSON to Struct glog.Infof("openID = ", openId.OpenId) glog.Infof("Session_key = ", openId.Session_key) glog.Infof("union_id = ",openId.UnionId) return openId, err }
这里就是go语言获取小程序unionId的代码了,用小程序的appId和秘钥还有前端传来的code做参数,调取微信的接口,事实上这就是获取微信小程序openId的代码,微信小程序只要放在开放平台上,小程序和对应的公众号进行关联,并且用户关注了相对应的公众号,符合这三点就可以获取到用户的unionId,如果有任何一点不符合,都获取不到。
如果不能达到以上三点,获取小程序的unionId还有一种方式,就是通过AES解密,另外一种方式相对来说就比较复杂了,所以我没有采用另外的一种方式。