实战:微信小程序授权获取用户手机号

645 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

1、背景

最近在做个需求,需要获取客户端的手机号,开始本以为小程序可以直接获取到,但是到后来前端告诉我需要后端调接口得到,人傻了,赶紧百度一下呗,但是找到的几乎都是以这种方式去获取的,但是我每一次调用成功的,返回的结果都是什么 code 无效之类的,没办法只好在官网上找了

String res = SendHttps.sendGet("https://api.weixin.qq.com/sns/jscode2session", "appid=" + appId + "&secret=" + appSecret + "&js_code=" + code + "&grant_type=authorization_code");

2、最新版本获取手机号步骤

小程序官网链接,点击进入:developers.weixin.qq.com/miniprogram…

2.1、获取access_token

在最新版本中,要想获取客户端的手机号需要2步,第一步获取 access_token

// 申请好小程序会有这二个值的
// appId:小程序的appId
// appSecret:小程序密钥

//调用微信接口获取access_token
String accessTokenResponse = SendHttpsUtil.sendGet(accessTokenUrl, "grant_type=client_credential&appid=" + appId + "&secret=" + appSecret);

//将返回结构进行格式化,获取真正的access_token的值
net.sf.json.JSONObject accessTokenResponseObject = net.sf.json.JSONObject.fromObject(accessTokenResponse);
String access_token = accessTokenResponseObject.getString("access_token");

2.2、通过code和access_token获取用户手机号

说实话,这个接口有点坑的,获取手机号是POST方法,但是access_token确实拼接在URL后面的,很多人一开始把 code 和 access_token二个参数都放到body中,就会调用失败

//拼接url,access_token就是2.1获取到的access_token的值
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + access_token;

//获取手机号,这里要注意的是 code是放在body里面的,access_token是放在URL上的
String res = SendHttpsUtil.doPost(code,url);
net.sf.json.JSONObject resultObject = net.sf.json.JSONObject.fromObject(res);
net.sf.json.JSONObject phoneInfoObject = net.sf.json.JSONObject.fromObject(resultObject.get("phone_info"));
String phoneNumber = phoneInfoObject.getString("phoneNumber");

3、完整代码

3.1、http调用工具类

package com.util;

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.apache.http.util.TextUtils;
import org.springframework.util.StreamUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SendHttpsUtil {

    /**
     * 向指定URL发送GET方法的请求
     *
     * @param url   发送请求的URL
     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return URL 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param) {
        String result = "";
        BufferedReader in = null;
        try {
            String urlNameString = url + "?" + param;
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 建立实际的连接
            connection.connect();
            // 获取所有响应头字段
            Map<String, List<String>> map = connection.getHeaderFields();
            // 遍历所有的响应头字段
            for (String key : map.keySet()) {
                System.out.println(key + "--->" + map.get(key));
            }
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(
                    connection.getInputStream(), "utf-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送GET请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }


    public static String doPost(String code,String url) {
        JSONObject jsonObject = JSONUtil.createObj();
        jsonObject.put("code", code);
        String body = HttpRequest
                .post(url)
                .header("Content-Type", "application/json")
                .body(jsonObject.toString())
                .execute()
                .body();
        return body;
    }
}

3.2、前端发送code参数到后端,后端返回客户端手机号


    @Value("${appSecret}")
    public String appId;

    @Value("${appSecret}")
    public String appSecret;

    @Value("${accessTokenUrl}")
    public String accessTokenUrl;

    @Value("${getPhoneUrl}")
    public String getPhoneUrl;

   /**
     * 获取客户端手机号
     */
    @PostMapping(value = "/getPhoneNumber", produces = "application/json;charset=utf-8")
    public R getPhoneNumber(@RequestBody SessionKeyDTO sessionKeyDTO) {
        JSONObject result = new JSONObject();
        String jsonPrettyStr = JSONUtil.toJsonPrettyStr(sessionKeyDTO);
        JSONObject object = JSON.parseObject(jsonPrettyStr);
        String code = object.getString("codeStr");
        if (StringUtil.isBlank(code)) {
            return R.fail("参数为空");
        }
        //获取access_token
        String accessTokenResponse = SendHttpsUtil.sendGet(accessTokenUrl, "grant_type=client_credential&appid=" + appId + "&secret=" + appSecret);
        net.sf.json.JSONObject accessTokenResponseObject = net.sf.json.JSONObject.fromObject(accessTokenResponse);
        String access_token = accessTokenResponseObject.getString("access_token");
        String url = getPhoneUrl + access_token;
        String res = SendHttpsUtil.doPost(code,url);
        net.sf.json.JSONObject resultObject = net.sf.json.JSONObject.fromObject(res);
        net.sf.json.JSONObject phoneInfoObject = net.sf.json.JSONObject.fromObject(resultObject.get("phone_info"));
        String phoneNumber = phoneInfoObject.getString("phoneNumber");
        result.put("mobile", phoneNumber);
        return R.ok(result);
    }

3.3、后端接收code参数DTO类

@Data
public class SessionKeyDTO{

     private String codeStr;
}

3.4、相关配置信息

appId: 你的appId
appSecret: 你的小程序密钥
accessTokenUrl: https://api.weixin.qq.com/cgi-bin/token
getPhoneUrl: https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=