草庐IT

微信小程序获取用户手机号码

陈大大的期待 2023-04-13 原文

编写日期 : 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?grant_type=client_credential&appid=APPID&secret=APPSECRET
这个比较简单,只要问前端拿到appidsecret就可以直接访问获取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>
        <!-- 阿里fastjson包JSON转换-->
        <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 + secret
            HttpResponse response = HttpRequest.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + 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下面,一次性放行了,四换一😁😁

有关微信小程序获取用户手机号码的更多相关文章

  1. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  2. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  3. ruby - 从 Ruby 中的主机名获取 IP 地址 - 2

    我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge

  4. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  5. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了ruby​​版本管理器,并将RVM安装的ruby​​实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby​​。有没有办法让emacs像shell一样尊重ruby​​的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el

  6. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  7. ruby-on-rails - 简单的 Ruby on Rails 问题——如何将评论附加到用户和文章? - 2

    我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。

  8. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  9. ruby - RVM "ERROR: Unable to checkout branch ."单用户 - 2

    我在新的Debian6VirtualBoxVM上安装RVM时遇到问题。我已经安装了所有需要的包并使用下载了安装脚本(curl-shttps://rvm.beginrescueend.com/install/rvm)>rvm,但以单个用户身份运行时bashrvm我收到以下错误消息:ERROR:Unabletocheckoutbranch.安装在这里停止,并且(据我所知)没有安装RVM的任何文件。如果我以root身份运行脚本(对于多用户安装),我会收到另一条消息:Successfullycheckedoutbranch''安装程序继续并指示成功,但未添加.rvm目录,甚至在修改我的.bas

  10. ruby - 没有类方法获取 Ruby 类名 - 2

    如何在Ruby中获取BasicObject实例的类名?例如,假设我有这个:classMyObjectSystem我怎样才能使这段代码成功?编辑:我发现Object的实例方法class被定义为returnrb_class_real(CLASS_OF(obj));。有什么方法可以从Ruby中使用它? 最佳答案 我花了一些时间研究irb并想出了这个:classBasicObjectdefclassklass=class这将为任何从BasicObject继承的对象提供一个#class您可以调用的方法。编辑评论中要求的进一步解释:假设你有对象

随机推荐