Overview
Obtaining a user's phone number in a WeChat Mini Program requires a multi-step process involving session key exchange and symmetric decryption. This guide covers the complete implementation using ASP.NET Core backend.
Step 1: Session Key Exchange
Frontend Login
In the Mini Program's app.js, invoke wx.login() to obtain an authorization code, then send it to your backend server.
// app.js
App({
onLaunch() {
wx.login({
success: res => {
if (res.code) {
wx.request({
url: 'https://localhost:7122/api/Login/GetSession',
data: { code: res.code },
success: data => {
this.globalData.sessionKey = data.data.session_key;
this.globalData.openId = data.data.openid;
}
});
}
}
});
},
globalData: {
sessionKey: '',
openId: ''
}
});
Backend Endpoint
Create a model class to hold the response:
public class SessionResponse
{
public string session_key { get; set; }
public string openid { get; set; }
}
Implement the controller endpoint that exchanges the code with WeChat's API:
[Route("api/Login")]
[ApiController]
public class LoginController : ControllerBase
{
[HttpGet("GetSession")]
public IActionResult GetSession(string code)
{
string appId = Configuration["WeChat:AppId"];
string appSecret = Configuration["WeChat:AppSecret"];
string requestUrl = $"https://api.weixin.qq.com/sns/jscode2session?appid={appId}&secret={appSecret}&js_code={code}&grant_type=authorization_code";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
request.Method = "GET";
request.ContentType = "text/html;charset=UTF-8";
using var response = (HttpWebResponse)request.GetResponse();
using var stream = response.GetResponseStream();
using var reader = new StreamReader(stream, Encoding.UTF8);
string jsonResponse = reader.ReadToEnd();
SessionResponse sessionData = JsonConvert.DeserializeObject<SessionResponse>(jsonResponse);
return Ok(sessionData);
}
}
Store sensitive credentials in appsettings.json:
{
"WeChat": {
"AppId": "your_appid",
"AppSecret": "your_secret"
}
}
Step 2: Phone Number Decryption
Frontend Request
In the page JavaScript file, handle the phone number button callback:
const app = getApp();
Page({
data: {
phoneNumber: '',
userNickname: '',
showInput: false
},
onChooseAvatar(e) {
this.setData({
userNickname: e.detail.avatarUrl,
showInput: true
});
},
onGetPhoneNumber(e) {
if (e.detail.errMsg === "getPhoneNumber:ok") {
wx.request({
url: 'https://localhost:7122/api/Login/DecryptPhone',
data: {
encryptedData: e.detail.encryptedData,
iv: e.detail.iv,
sessionKey: app.globalData.sessionKey
},
method: "GET",
success: res => {
this.setData({
phoneNumber: res.data
});
}
});
}
}
});
Backend Decryption Endpoint
[HttpGet("DecryptPhone")]
public IActionResult DecryptPhone(string encryptedData, string iv, string sessionKey)
{
string phone = DecryptPhoneNumber(encryptedData, iv, sessionKey);
return Ok(phone);
}
private string DecryptPhoneNumber(string encryptedData, string iv, string sessionKey)
{
try
{
byte[] encryptedBytes = Convert.FromBase64String(encryptedData);
byte[] keyBytes = Convert.FromBase64String(sessionKey);
byte[] ivBytes = Convert.FromBase64String(iv);
using var aesCipher = new AesManaged
{
Key = keyBytes,
IV = ivBytes,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
ICryptoTransform decryptor = aesCipher.CreateDecryptor();
byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
string jsonResult = Encoding.UTF8.GetString(decryptedBytes);
JObject phoneData = JObject.Parse(jsonResult);
return phoneData["phoneNumber"]?.ToString() ?? string.Empty;
}
catch
{
return string.Empty;
}
}
Technical Details
Session Key Flow
The jscode2session API returns a session_key that serves as the crpytographic key for decrypting user data. This key is tied to the user's session and should not be exposed client-side.
Decryption Algorithm
The phone number data is encrypted using AES-128-CBC with PKCS7 padding. The decryption process requires:
- Key: The session key obtained from WeChat
- IV: The initialization vector provided by the frontend
- Encrypted Data: The encrypted phone number payload
Security Considerations
- Store
AppIdandAppSecretin configuration files, never hardcode them - The session key should be handled securely on the server
- Use HTTPS for all API communications
- Session keys expire and should be refreshed when needed
WXML Template Structure
<button
type="primary"
open-type="getPhoneNumber"
bindgetphonenumber="onGetPhoneNumber">
Get Phone Number
</button>
The button triggers the onGetPhoneNumber callback which receives the encrypted payload containing the user's phone information.