O pagamento via Contas Oficiais (JSAPI) é uma das formas mais comuns de transação no ecossistema WeChat. Ele permite que usuários realizem compras diretamente através de links em menus ou mensagens dentro do aplicativo. Neste guia, abordaremos a implementação técnica dessa funcionalidade utilizando .NET MVC e JavaScript.
1. Configurações Preliminares
Antes de iniciar a codificação, é necessário garantir que o ambiente no Portal do Merchant do WeChat Pay e na Plataforma de Desenvolvedor esteja configurado:
- Diretório de Pagamento: Defina a URL exata onde o pagamento será processado.
- Domínio de Autenticação OAuth2: Configure o domínio para obtenção do OpenID do usuário.
- Whitelist de IPs: Registre o IP do servidor que fará as chamadas de API.
2. Fluxo de Autenticação e Obtenção de OpenID
Para processar um pagamento JSAPI, o sistema precisa do openid do usuário. Isso é feito através do fluxo de redirecionamento OAuth2 do WeChat.
// Controller: Gerenciamento de Autenticação
public class CheckoutController : Controller
{
public ActionResult Index()
{
if (Session["UserOpenId"] == null)
{
PrepareAuthentication();
}
return View();
}
private void PrepareAuthentication()
{
string currentUrl = Request.Url.AbsoluteUri;
if (Session["AuthCode"] == null)
{
// Construção da URL de autorização do WeChat
var authUrl = string.Format(
"https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope=snsapi_base#wechat_redirect",
WechatConfig.AppId,
HttpUtility.UrlEncode(currentUrl)
);
Session["RedirectUrl"] = authUrl;
}
}
[HttpPost]
public JsonResult RequestAuthUrl()
{
return Json(new { url = Session["RedirectUrl"]?.ToString() });
}
}
3. Implementação do Frontend (JavaScript)
O frontend é responsável por capturar o código de autorização na URL, obter os parâmetros de pagamento do servidor e invocar a ponte de comunicação do WeChat (WeixinJSBridge).
$(function() {
const urlParams = new URLSearchParams(window.location.search);
const authCode = urlParams.get('code');
if (authCode) {
// Envia o código para o servidor para obter o OpenID
$.post('/Checkout/InitializeSession', { code: authCode });
} else {
// Busca URL de redirecionamento se não houver código
$.post('/Checkout/RequestAuthUrl', function(response) {
if (response.url) window.location.href = response.url;
});
}
});
function initWechatPayment() {
const amount = $('#paymentAmount').val();
if (!amount || amount <= 0) {
alert('Insira um valor válido');
return;
}
$.ajax({
url: '/Checkout/CreatePaymentOrder',
type: 'POST',
data: { total: amount },
success: function(config) {
invokeWechatPay(config);
},
error: function() {
alert('Erro ao processar transação.');
}
});
}
function invokeWechatPay(config) {
if (typeof WeixinJSBridge == "undefined") {
document.addEventListener('WeixinJSBridgeReady', () => onBridgeReady(config), false);
} else {
onBridgeReady(config);
}
}
function onBridgeReady(config) {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": config.appId,
"timeStamp": config.timeStamp,
"nonceStr": config.nonceStr,
"package": config.packageValue,
"signType": "MD5",
"paySign": config.paySign
},
function(res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
window.location.href = "/Checkout/Success";
}
}
);
}
4. Processamento da Ordem Unificada no Backend
O servidor deve realizar a chamada de "Unified Order" para o WeChat Pay e retornar os parâmetros assinados para o frontend.
[HttpPost]
public JsonResult CreatePaymentOrder(decimal total)
{
try
{
// Converte valor para centavos (requisito do WeChat Pay)
int amountInCents = (int)(total * 100);
string openId = Session["UserOpenId"].ToString();
// Parâmetros para a Unified Order
JsapiPayHandler handler = new JsapiPayHandler();
var unifiedResult = handler.GenerateUnifiedOrder(amountInCents, openId);
// Gera os parâmetros para o JSAPI (appId, timeStamp, nonceStr, package, paySign)
var jsParams = handler.GetJsApiParameters(unifiedResult);
return Json(new {
appId = jsParams.Get("appId"),
timeStamp = jsParams.Get("timeStamp"),
nonceStr = jsParams.Get("nonceStr"),
packageValue = jsParams.Get("package"),
paySign = jsParams.Get("paySign"),
status = "success"
});
}
catch (Exception ex)
{
return Json(new { status = "error", message = ex.Message });
}
}
5. Requisitos de Segurança
Para evitar alertas de segurança do navegaodr dentro do WeChat ("Não insira senhas nesta página"), é imprescindível configurar o Domínio de Negócios Confiável nas configurações da Conta Oficial. Isso remove tarjas de aviso e melhora a taxa de conversão.
Além disso, certifique-se de validar as notificações de pagamento (Webhooks) no backend para confirmar se a transação foi realmente concluída com sucesso antes de liberar o produto ou serviço ao cliente.