编写日期 : 2022-10-21

写这篇文章原因

公司有个小程序授权登录 ,我后端需要拿到微信的手机号(phoneNumber)和微信用户唯一识别id(unionid)。

我和前端都没搞过这个,前端说要拿到这两个值需要我后端支持,然后我也开始看网上是如何去拿到这两个值的,但是呢 ,现在这网上的教程不是代码缺胳膊少腿的要不就是很久之前的教程了,现在微信小程序提供的接口用以前的方法不适用了(听说微信小程序官方每逢佳节改接口,前端说的,我后端不是特别清楚这小程序的官方,不过是挺狗的)。搞了好一会儿我和前端两个人都没有成功拿到这两个参数,然后看小程序官方文档说要认证企业才拿的到手机号(从getInfo这个接口拿),然后找老大认证了下企业,说是要3-5天,第二天就认证好了。手机号前端拿是拿到了,但是中间的四位数是带*的,这小程序官方,哎,又得继续整活,然后有看教程说把前端的参数encryptedData解密就能拿到手机号等一系列信息,我按照网上的帖子给解密了 ,但是里面并没有手机号和uid字段,但是我看网上帖子的解密截图是有的,这大概又是小程序官方为了什么信息安全改了接口返回信息内容。

encryptedData解密内容,我对我的内容做了修改展示出来了

result = {"openId":"okhjshakdjkasdnasjdad","nickName":"微信用户","gender":0,"language":"","city":"","province":"","country":"","avatarUrl":"https://thirdwx.qlogo.cn/asdjkasjdajk/asklhdjkasjkda/sakda/1311","watermark":{"timestamp":1123213136,"appid":"wxksahdahsjkdhaks"}}

这时候前端又说要拿到unionid得绑定微信开放平台账号后就可以直接访问微信小程序官方的接口拿到

绑定后就拿到了

这会儿好了就剩下手机号码了

获取手机号码

我们获取手机号 先要获取小程序全局唯一后台接口调用凭据 access_token,然后拿着这个 access_token 和动态令牌code去获取手机号码,我分开介绍这两步:

获取access_token

小程序官方文档的截图
链接: >>>小程序官方文档 <<<

请求路径

GET
https://api.weixin.qq.com/cgi-bin/token" />

接口会返回access_token和 token凭证有效时间expires_in,单位:秒。目前是7200秒之内的值。

获取手机号码

链接: >>>小程序官方文档 <<<

这块看文档大概也就知道了 ,直接上全部的代码了

yaml

pom.xml

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.57</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.16</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency>

controller

@Value("${wx.xiaochengxu.appid}")private String appid;@Value("${wx.xiaochengxu.secret}")private String secret;@PostMapping("/getPhoneNum")@ApiOperation("微信小程序获取手机号")public R getPhoneNum(@RequestBody Map<String , String> map){if (map.get("code")!=null && map.get("code").length()!=0 ){String code = map.get("code");//先获取access_token = appid + secretHttpResponse response = HttpRequest.get("https://api.weixin.qq.com/cgi-bin/token" /> + appid + "&secret=" + secret + "").execute();JSONObject tokenJson = JSON.parseObject(response.body());if(!tokenJson.containsKey("access_token")){throw new CommonException("501","微信官方修改了获取access_token令牌接口!");}String accessToken =tokenJson.get("access_token").toString();//用 access_token + code 获取手机号JSONObject jsonCode = new JSONObject();jsonCode.put("code",code);String resPhone = HttpUtil.post("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken, jsonCode.toString());if(StringUtils.isEmpty(resPhone) || !resPhone.contains("phone_info") ||!resPhone.contains("phoneNumber")){throw new CommonException("501","微信官方修改了小程序获取用户手机号码相关接口!");}JSONObject resPhoneInfo = JSON.parseObject(resPhone);JSONObject phoneInfo=resPhoneInfo.getJSONObject("phone_info");System.out.println(resPhoneInfo);System.out.println(phoneInfo);String phoneNumber = phoneInfo.get("phoneNumber").toString();return R.SUCCESS.setNewData(MapUtil.builder().put("phoneNumber",phoneNumber).build());}return null;}

注意:我这个Java代码里面抛出得异常是我自己定义得异常,你们在用的时候可以看你们自己得心情,爱咋搞都行,反正正常情况下不会出现异常得,除非小程序官方又又又改了接口

访问结果

对结果进行格式不变的胡乱内容修改后展示,我们的代码是将请求结果中的phoneNumber单独拿出来返回的,看前端咋说,他要啥就给啥

{"errcode":0,"errmsg":"ok","phone_info":{"phoneNumber":"15812341234","watermark":{"appid":"vxsjkhakhdjka","timestamp":827319823},"purePhoneNumber":"15812341234","countryCode":"12"}}

获取unionid

本来我以为这个需求到这里就结束了,前端和我说他获取uid的代码明文暴露了小程序 appId小程序 appSecret,这样不安全而且代码审核也过不了,所以还需要我再支持下接口,这个接口就比较简单了
Get请求直接拼接访问就行。

链接: >>>小程序官方文档 <<<

@PostMapping(value = "/getWXUid")@ApiOperation("微信小程序获取微信用户唯一标识uid")public R getWXUid(@RequestBody Map<String , String> map){String jsCode = map.get("jsCode");HttpResponse response = HttpRequest.get("https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+jsCode+"&grant_type=authorization_code"+"").execute();JSONObject wxInfo = JSON.parseObject(response.body());String unionid = wxInfo.get("unionid").toString();String openid = wxInfo.get("openid").toString();String session_key = wxInfo.get("session_key").toString();return R.SUCCESS.setNewData(MapUtil.builder().put("unionid",unionid).put("openid",openid).put("session_key",session_key).build());}

总结

申明: 本文代码经过本人亲测,并在项目中实施可用供大家借鉴,但是微信小程序官方说不定哪天就改了接口什么的,所以我只能保证在发文前好使,后面你们在看好不好使就不知道喽
发文时间:2022-10-21

在搞这个的时候,我还了解到了一个东西,就是在使用Shiro安全框架的时候,放行规则不能超过12个,不然这个安全框架会把你放行的接口也拦截,前面也不知道要配合前端写几个接口,我写一个放行一个,到写getUid接口的时候,我用Swagger文档进行测试的时候,这个文档的页面被拦截的,然后我简单的排查一下,我就猜这玩意是不是放行超过了限制,我一搜,哎,还真是,我就把login和这三个接口写到一个controller下面,一次性放行了,四换一