微信小程序获取用户手机号前后台流程(附代码)

前置条件

1.首先获取手机号需要认证企业资质的小程序

2.获取手机号需要一台服务器编写解密代码

正文

1.首先理一下流程,下面是微信开发文档中的一张图

下面是我自己写的流程 

 

注意

微信官方文档-手机号获取

 按照例程打印不出来code,看看答应e.detail的结果

{
errMsg: "getPhoneNumber:ok", 
encryptedData: "/7uD9+GJ7qd0YBVX30Fg0Fj8W/2IXHbUhzZ3TfHv+LyRktBtZw…KKLFhmzK5jyiLxweSspezjVP7EEaifXPaAFeGG4fIl3u4GQ==", 
iv: "jfnSdhGbU4OS3JmwsoxL2Q=="
}

只能获取encryptedData和iv因此我们需要从wx.login()中获取code

2.小程序代码

1.在app.js的onLaunch()或index.js页面的onLoad()下面写wx.login()

App({
  /**
   * 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
   */
  onLaunch: function () {
// 1.获取临时登录凭证code
        wx.login({
          success: res => {
            if(res.code){
              console.log("code->", res.code)
              wx.setStorageSync('resCode', res.code)
            }
          }
        })
}
})

将获取到的code保存在缓存里

2.由于getPhoneNumber现在不支持自动弹出,需要用按钮去拉起,所以我们在wxml写上

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>

并且在对应的js里写

Page({
// 获取手机号授权
getPhoneNumber (e)  {
    // 用户拒绝授权
    if(e.detail.errMsg == "getPhoneNumber:fail user deny") {
      wx.showToast({
        icon: "none",
        title: '请允许获取手机号,否则功能不可用!',
      })
      return
    }
    /// 用户允许授权
    console.log("e.detail.errMsg="+e.detail.errMsg)
    console.log("e.detail.iv=->", e.detail.iv); //包括敏感数据在内的完整用户信息的加密数据,需要解密
    console.log("e.detail.encryptedData->", e.detail.encryptedData); //加密算法的初始向量,解密需要用到

    /// 获取手机号
    let resCode = wx.getStorageSync('resCode');
    console.log("resCode = " +resCode)
    console.log("  e.detail = " +  e.detail)

    if(resCode){
      this.getphone(resCode, e.detail.encryptedData, e.detail.iv);
      this.triggerEvent("isHiddenPopup");
    }
  },
// 访问登录凭证校验接口获取session_key 并用session_key获取手机号
getphone: function(js_code, encryptedData, iv) {
  wx.request({
    url: globalData.getSessionKeyUrl,//需要填写自己的服务器请求地址
    data: {
        'js_code': js_code,
        'encryptedData' : encryptedData,
        'iv':iv,
        'sign': 'sign',
    },
    method: 'GET', 
    header: {
        'content-type': 'application/json'
    }, // 设置请求的 header
    success: function(data) {
      console.log("获取手机号返回JSON数据 =", data.data)
      console.log("手机号 = "+data.data.phoneNumber)
      if(data.data==undefined){
        wx.showToast({
          icon: "none",
          title: '手机号获取失败,请重新登录!',
        })
        return
      }
      if(data.statusCode == 200) { 
        if(data.data.phoneNumber==undefined){
          // 获取手机号失败 
            console.log("获取手机号失败");
            return
          }
          // 4.跳转web-view页面
          wx.switchTab({
            url: "/pages/mine/mine"
          }) 
        }
    },
    fail: function(err) {
        console.log(err);
        wx.showToast({
          icon: "none",
          title: 'session_key获取失败,请重新登录!',
        })
        return
    }
  })
}
})

至此小程序主要代码写完了

3.后台代码

后台选择SpringBoot搭建,首先建一个基础工程,然后直接贴代码

1.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.server</groupId>
    <artifactId>server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>server</name>
    <description>server</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.11.1</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.15</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16 -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk16</artifactId>
            <version>1.46</version>
        </dependency>


    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2.ServerApplication.java 

package com.server;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.server.data.globalData;
import com.server.httpUtil.PostData;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.web.bind.annotation.*;


@RestController
@SpringBootApplication
public class ServerApplication {
    com.server.data.globalData globalData = new globalData();
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }
    //解析电话号码
    @GetMapping("/getsessionkey")
    public Object getsessionkey(String js_code,String encryptedData, String iv) throws JsonProcessingException {
        PostData PostData = new PostData();
        String responseData =  PostData.PostData(globalData.url, globalData.appid, globalData.secret,js_code,globalData.grant_type);
        //获取SessionKey 和openid
        ObjectMapper mapper = new ObjectMapper();
        JsonNode resData = mapper.readTree(responseData);
        try{
            if(resData.get("session_key").asText()!=null)
            {
                String SessionKey = resData.get("session_key").asText();
                String openid = resData.get("openid").asText();
                System.out.println("SessionKey="+SessionKey);
                System.out.println("openid="+openid);
                System.out.println("encryptedData="+encryptedData);
                System.out.println("iv="+iv);
                String wxDecrypt = WechatUtils.wxDecrypt(encryptedData,SessionKey,iv);
                System.out.println(wxDecrypt);
                return wxDecrypt;
            }else {
                System.out.println("请求微信服务器异常");
            }

        }catch (Exception e)
        {
            System.out.println("请求微信服务器异常");
        }
        return 0;
    }
}

3.WechatUtils.java解密工具类

package com.server;

import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class WechatUtils {
    public static final String AES = "AES";
    public static final String AES_CBC_PADDING = "AES/CBC/PKCS7Padding";

    /**
     *    * 微信 数据解密<br/>
     *    * 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充<br/>
     *    * 对称解密的目标密文:encrypted=Base64_Decode(encryptData)<br/>
     *    * 对称解密秘钥:key = Base64_Decode(session_key),aeskey是16字节<br/>
     *    * 对称解密算法初始向量:iv = Base64_Decode(iv),同样是16字节<br/>
     *    *
     *    * @param encrypted 目标密文
     *    * @param session_key 会话ID
     *    * @param iv 加密算法的初始向量
     *
     */
    public static String wxDecrypt(String encrypted, String session_key, String iv) {
        String result = null;
        byte[] encrypted64 = org.apache.commons.codec.binary.Base64.decodeBase64(encrypted);
        byte[] key64 = org.apache.commons.codec.binary.Base64.decodeBase64(session_key);
        byte[] iv64 = org.apache.commons.codec.binary.Base64.decodeBase64(iv);
        try {
            init();
            result = new String(decrypt(encrypted64, key64, generateIV(iv64)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     *    * 初始化密钥
     *
     */
    public static void init() throws Exception {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        KeyGenerator.getInstance(AES).init(128);
    }

    /**
     *    * 生成iv
     *
     */
    public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
        // iv 为一个 16 字节的数组,这里采用和 iOS 端一样的构造方法,数据全为0
        // Arrays.fill(iv, (byte) 0x00);
        AlgorithmParameters params = AlgorithmParameters.getInstance(AES);
        params.init(new IvParameterSpec(iv));
        return params;
    }
    /**
     *    * 生成解密
     *
     */
    public static byte[] decrypt(byte[] encryptedData, byte[] keyBytes, AlgorithmParameters iv)
            throws Exception {
        Key key = new SecretKeySpec(keyBytes, AES);
        Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
        // 设置为解密模式
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        return cipher.doFinal(encryptedData);
    }
}

4.HttpRestUtils.java http请求工具类

package com.server.httpUtil;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
public class HttpRestUtils {
    /**
     * http post
     * */
    public static String post(String url, MultiValueMap<String, String> params) throws IOException {
        return  httpRestClient(url, HttpMethod.POST, params);
    }

    /**
     * http get
     * */
    public static String get(String url, MultiValueMap<String, String> params) throws IOException {
        return  httpRestClient(url, HttpMethod.GET, params);
    }

    /**
     * HttpMethod  post/get
     * */
    private static String httpRestClient(String url, HttpMethod method, MultiValueMap<String, String> params) throws IOException {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(10*1000);
        requestFactory.setReadTimeout(10*1000);
        RestTemplate client = new RestTemplate(requestFactory);
        HttpHeaders headers = new HttpHeaders();
        // 以表单的方式提交
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
//       headers.setContentType(MediaType.APPLICATION_JSON_UTF8);//不好使,不能用get方法
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(params, headers);
        //  执行HTTP请求
        ResponseEntity<String> response = null;
        try{
            response = client.exchange(url, HttpMethod.POST, requestEntity, String.class);
            System.out.println("response="+response);
            return response.getBody();
        }
        catch (HttpClientErrorException e){
            System.out.println( "------------- 出现异常 HttpClientErrorException -------------");
            System.out.println(e.getMessage());
            System.out.println(e.getStatusText());
            System.out.println( "-------------responseBody-------------");
            System.out.println( e.getResponseBodyAsString());
            e.printStackTrace();
            return "";
        }
        catch (Exception e) {
            System.out.println( "------------- HttpRestUtils.httpRestClient() 出现异常 Exception -------------");
            System.out.println(e.getMessage());
            return "";
        }


    }
}

5.PostData.java http请求业务类

package com.server.httpUtil;
import org.springframework.http.HttpMethod;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

public class PostData {
    public String PostData(String url ,String appid,String appSecret,String code,String authorization_code) {
        try {
            //post请求
            HttpMethod method = HttpMethod.GET;
            // 封装参数,千万不要替换为Map与HashMap,否则参数无法传递
            MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
            params.add("appid",appid);
            params.add("secret",appSecret);
            params.add("js_code",code);
            params.add("grant_type",authorization_code);
            System.out.print("发送数据:" + params.toString()+"\n");
            //发送http请求并返回结果
            String result = HttpRestUtils.get(url, params);
            System.out.print("接收反馈:" + result+"\n");
            return result;
        } catch (Exception e) {
            System.out.println("------------- " + this.getClass().toString() + ".PostData() : 出现异常 Exception -------------");
            System.out.println(e.getMessage());
            return "";
        }
    }
}

6.globalData.java 全局变量

package com.server.data;

public class globalData {
    public String  url = "https://api.weixin.qq.com/sns/jscode2session";//微信服务器接口
    public String  appid = "xxxxxx填自己小程序的xxxxx";
    public String  secret = "xxxxxx填自己小程序的xxxxx";
    public String  grant_type = "authorization_code";//这样写就行
}

至此前后台就ok了,可以获取用户手机号了

后台数据打印如下

 

  • 14
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Y_Hungry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值