软件开发者:微信小程序获取用户手机号

软件开发者:微信小程序获取用户手机号

解决方案goocz2025-07-09 14:36:252A+A-

在微信小程序中通过获取用户手机号实现登录验证的完整流程如下:


一、准备工作

  1. 微信认证
  2. 小程序必须已完成微信认证(非个人主体)
  3. 权限配置
  4. 在小程序管理后台的 开发 > 开发管理 > 接口设置 中开通 获取手机号 权限

二、前端实现流程

步骤1:用户登录凭证获取

// 获取临时登录凭证 code
wx.login({
  success: (res) => {
    if (res.code) {
      // 将 code 发送到开发者服务器
      this.sendCodeToServer(res.code)
    } else {
      console.error('登录失败:' + res.errMsg)
    }
  }
})

步骤2:添加手机号获取按钮

<button 
  open-type="getPhoneNumber" 
  @getphonenumber="handleGetPhone"
  type="primary"
>授权手机号登录</button>

步骤3:处理授权回调

methods: {
  handleGetPhone(e) {
    if (e.detail.errMsg === 'getPhoneNumber:ok') {
      // 获取加密数据
      const { encryptedData, iv } = e.detail
      
      // 发送加密数据到服务器解密
      wx.request({
        url: 'https://yourdomain.com/api/decrypt-phone',
        method: 'POST',
        data: {
          encryptedData,
          iv,
          code: this.loginCode // 之前获取的登录凭证
        },
        success: (res) => {
          // 处理服务器返回的解密后手机号
          console.log('用户手机号:', res.data.phoneNumber)
        }
      })
    } else {
      console.error('用户拒绝授权')
    }
  }
}

三、后端处理流程(JAVA处理)

步骤1:获取 session_key (HTTP 请求工具类)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import com.alibaba.fastjson.JSONObject;

public class WeChatUtils {
    // 获取 session_key 和 openid
    public static JSONObject getSessionInfo(String code, String appId, String appSecret) {
        String urlStr = "https://api.weixin.qq.com/sns/jscode2session?" +
                "appid=" + appId +
                "&secret=" + appSecret +
                "&js_code=" + code +
                "&grant_type=authorization_code";

        try {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuilder response = new StringBuilder();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();
            
            return JSONObject.parseObject(response.toString());
        } catch (Exception e) {
            throw new RuntimeException("获取 session_key 失败", e);
        }
    }
}

步骤2:手机号解密工具类

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class PhoneDecryptor {

    // 解密手机号
    public static String decryptPhone(String encryptedData, String iv, String sessionKey) {
        try {
            // Base64 解码
            byte[] encryptedDataBytes = Base64.getDecoder().decode(encryptedData);
            byte[] ivBytes = Base64.getDecoder().decode(iv);
            byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey);

            // AES 解密
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keySpec = new SecretKeySpec(sessionKeyBytes, "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            
            byte[] decryptedBytes = cipher.doFinal(encryptedDataBytes);
            
            // 处理 PKCS#7 填充
            int pad = decryptedBytes[decryptedBytes.length - 1];
            byte[] data = new byte[decryptedBytes.length - pad];
            System.arraycopy(decryptedBytes, 0, data, 0, data.length);
            
            // 解析 JSON
            String result = new String(data, StandardCharsets.UTF_8);
            return JSONObject.parseObject(result).getString("phoneNumber");
        } catch (Exception e) {
            throw new RuntimeException("手机号解密失败", e);
        }
    }
}

步骤3:Controller 层示例(Spring Boot)

import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoginController {

    private static final String APP_ID = "your_appid";
    private static final String APP_SECRET = "your_secret";

    @PostMapping("/login")
    public String login(@RequestBody LoginRequest request) {
        // 1. 获取 session_key
        JSONObject sessionInfo = WeChatUtils.getSessionInfo(
                request.getCode(), 
                APP_ID, 
                APP_SECRET
        );
        
        // 2. 解密手机号
        String phoneNumber = PhoneDecryptor.decryptPhone(
                request.getEncryptedData(),
                request.getIv(),
                sessionInfo.getString("session_key")
        );
        
        // 3. 业务处理(保存用户信息等)
        return "登录成功,手机号:" + phoneNumber;
    }
}

// 请求参数 DTO
class LoginRequest {
    private String code;
    private String encryptedData;
    private String iv;
    
    // getters & setters
}

步骤4:Maven 依赖

<dependencies>
    <!-- FastJSON -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.83</version>
    </dependency>
    
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

四、安全注意事项

  1. 会话密钥管理
  2. session_key 的有效期为 5 分钟,且每次登录会刷新
  3. 加密验证
  4. 必须验证 encryptedData 和 iv 的完整性
  5. 防重放攻击
  6. 对解密请求添加时效性验证(建议 5 分钟内有效)
  7. 数据存储
  8. 手机号等敏感信息需加密存储(如 AES-256)

五、错误处理方案

错误场景

处理方案

用户拒绝授权

显示引导提示,允许手动输入手机号

网络请求失败

自动重试机制 + 友好错误提示

session_key 失效

重新执行登录流程获取新 code

解密失败

日志记录 + 人工审核流程



点击这里复制本文地址 以上内容由goocz整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

果子教程网 © All Rights Reserved.  蜀ICP备2024111239号-5