Payment Architecture Overview
The payment integration involves three main participants: the user, the mini program client, and the backend server. The flow spans from user authentication through order creation, payment initialization, transaction execution, and order verification.
User Interaction Flow
- User browses products and adds items to cart
- User submits order request
- Mini program redirects to payment confirmation
- User completes payment via WeChat
- System confirms payment and updates order status
Technical Implementation
Authentication and Token Acquisition
Before creating orders, the mini program must authenticate users and obtain a valid session. The button component with getUserInfo provides user details, while wx.login() retrieves the login code for backend verification.
async function authenticateUser(event) {
const { encryptedData, rawData, iv, signature } = event.detail;
const { code } = await wxLogin();
const authParams = {
encryptedData,
rawData,
iv,
signature,
code
};
const { token } = await apiRequest({
url: "/auth/wechat-login",
data: authParams,
method: "POST"
});
wx.setStorageSync('authToken', token);
return token;
}
The backend uses auth.code2Session to exchange the code for openid and session_key, then issues a token for subsequent API requests.
Order Creation
With the token stored, include it in the Authorization header for protected endpoints:
async function createOrder(orderData) {
const authHeader = {
Authorization: wx.getStorageSync('authToken')
};
const response = await apiRequest({
url: "/orders/create",
method: "POST",
data: orderData,
header: authHeader
});
return response.orderId;
}
Prepayment Processing
Send the order number to the backend, which validates the pending status and calls the WeChat unified order API:
async function initiatePrepayment(orderId) {
const paymentConfig = await apiRequest({
url: "/payment/prepare",
method: "POST",
data: { orderId },
header: { "content-type": "application/x-www-form-urlencoded" }
});
return paymentConfig;
}
The backend constructs a signed request to https://api.mch.weixin.qq.com/pay/unifiedorder and returns the prepay_id along with other rqeuired parameters.
Backend Random String Generation
Java utility for generating nonce strings:
public class PaymentUtils {
public static String generateNonceString(int length) {
String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random generator = new Random();
StringBuilder nonce = new StringBuilder();
for (int i = 0; i < length; i++) {
int index = generator.nextInt(chars.length());
nonce.append(chars.charAt(index));
}
return nonce.toString();
}
}
Signature Generation Process
Signatures ensure request integrity. Follow these steps:
- Collect all parameters except
signinto map M - Sort keys alphabetically (ASCII order)
- Concatenate as
key1=value1&key2=value2forming stringA - Append
&key=+ merchant secret key to stringA - Compute MD5 hash of the combined string
- Convert result to uppercase
Merchant key location: WeChat Merchant Platform → Account Settings → API Security → Key Setup
Java Signature Implementation
public class SignatureVerifier {
public static String createSignature(Map<String, Object> parameters,
String merchantKey) {
Set<String> keySet = parameters.keySet();
String[] sortedKeys = keySet.toArray(new String[0]);
Arrays.sort(sortedKeys);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < sortedKeys.length; i++) {
String key = sortedKeys[i];
Object value = parameters.get(key);
if (i > 0) {
builder.append("&");
}
builder.append(key).append("=").append(value != null ? value : "");
}
builder.append("&key=").append(merchantKey);
return md5UpperCase(builder.toString());
}
private static String md5UpperCase(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes("UTF-8"));
StringBuilder hex = new StringBuilder();
for (byte b : digest) {
String hexStr = Integer.toHexString(b & 0xFF);
if (hexStr.length() == 1) {
hex.append("0");
}
hex.append(hexStr);
}
return hex.toString().toUpperCase();
} catch (Exception e) {
throw new RuntimeException("MD5 computation failed", e);
}
}
}
Executing Payment
Once the backend returns payment parameters, trigger the native WeChat payment dialog:
async function executePayment(paymentParams) {
try {
await wx.requestPayment({
timeStamp: paymentParams.timeStamp,
nonceStr: paymentParams.nonceStr,
package: paymentParams.package,
signType: paymentParams.signType || 'MD5',
paySign: paymentParams.paySign
});
console.log('Payment successful');
} catch (error) {
console.error('Payment failed:', error);
}
}
Order Status Verification
After payment attempts, verify the order state through the backend:
async function verifyOrderStatus(orderId) {
const status = await apiRequest({
url: "/orders/status",
method: "POST",
data: { orderId }
});
return status;
}
Security Considerations
- Never expose merchant keys in client-side code
- Always validaet order status server-side after payment callbacks
- Use HTTPS for all API communications
- Implement idempotency for order creation to prevent duplicates
- Store
session_keysecurely and never transmit it unnecessarily