понедельник, 3 декабря 2012 г.

UPC eCommerceConnect Интеграция на платформе .NET: Часть 2. Программирование

Это вторая часть цикла статей, посвященных интеграции UPC
ВСЕ ЧАСТИ МАТЕРИАЛА

Пример на ASP.NET MVC3
Теперь собственно этап программирования

что имеем:
1. на руках есть XXXXXXX.pem файл с приватным ключем, с помощью которого нужно по определенным правилом зашифровать сообщение
2. раздел документации: "Интерфейс взаимодействия. Руководство администратора торговой системы."
http://ecommerce.upc.ua/docs/shop_gateway_interface.pdf

3. тема на форуме "Пример подключения для платформы .net со всеми деталями"
http://forum.ecommerce.upc.ua/viewtopic.php?f=12&t=468
(скажу сразу, что пример помог, но часть процедур пришлось додумывать самостоятельно)

1. Готовим объект - шлюз
Этот объект нам нужен для отображения полей формы
Как-то так. Если где ошибся с типами, вопросы/пожелания/предложения принимаются.
public class objectEccGateway: MegaUtils_V3.objects.objectMegaBase
{
public int Version;
public string MerchantID;
public string TerminalID;
public long TotalAmount;
public int Currency;
public string Locale; //ru
public string OrderID;
public string PurchaseTime;
public string Gateway;
public string SD;
public string PurchaseDesc;

public string XID;
public string ProxyPanResponse;
public string ApprovalCode;
public int TranCode;
public Int64 Rrn;

public string Signature;
}

2. Готовим объект - параметры системы
В этом объекте я настраивал параметры системы UPC

public class objectCatalogPaymentSystemUPC
{
public string MerchantId;

public string TerminalId;

public string CertificateFile;

public string Gateway;

}

3. Готовим утилиты для работы с файлами ключей

для парсинга приватного ключа из *.pem файла
помогло решение из статьи
http://stackoverflow.com/questions/1162504/decrypting-with-private-key-from-pem-file-in-c-sharp-with-net-crypto-library/1162519#1162519
в статье есть ссылка на файл
http://www.jensign.com/opensslkey/opensslkey.cs

который я взял и полностью вставил в код

(правда одну строчку пришлось закомментиовать там было "(сертификат)UI" - .NET не распознал её как идентификатор. на работоспособности системы она не отразилась)

эта статья тоже ссылается на правильное решение
http://stackoverflow.com/questions/243646/how-to-read-a-pem-rsa-private-key-from-net

также помогла функция PEM отсюда
http://pages.infinit.net/ctech/20040812-0816.html

на эту функцию вела статья
http://social.msdn.microsoft.com/Forums/en-US/Vsexpressvcs/thread/348e1909-4da9-4980-94fc-f412dce07690/

в конце концов код выглядел так:

public class RSACryptoUtils
{
public static string RSASign(string data, string KeyFile)
{

RSACryptoServiceProvider rsaCsp =
LoadCertificateFile(KeyFile);

if (rsaCsp == null) return String.Empty;

byte[] dataBytes = Encoding.UTF8.GetBytes(data);

byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA1");

return Convert.ToBase64String(signatureBytes);

}

public static byte[] PEM(string type, byte[] data)
{
string pem = Encoding.ASCII.GetString(data);
string header = String.Format("-----BEGIN {0}-----", type);
string footer = String.Format("-----END {0}-----", type);
int start = pem.IndexOf(header) + header.Length;
int end = pem.IndexOf(footer, start);
string base64 = pem.Substring(start, (end - start));
return Convert.FromBase64String(base64);
}


public static RSACryptoServiceProvider LoadCertificateFile(string filename)
{
using (FileStream fs = File.OpenRead(filename))
{
byte[] data = new byte[fs.Length];
fs.Read(data, 0, data.Length);

if (data[0] != 0x30)
{
// maybe it's ASCII PEM base64 encoded ?
data = PEM("RSA PRIVATE KEY", data);
}
if (data != null)
return opensslkey.DecodeRSAPrivateKey(data);
//x509 = new X509Certificate2(data);

throw new ApplicationException("error");

}
//return x509;
throw new ApplicationException("error");
}
}
4. Готовим функцию, которая возвращает объект "поля формы"
/// <summary>
/// Подготовить поля веб-формы для отправки на сервер
/// </summary>
/// <param name="aUPCParams">параметры мерчанта</param>
/// <param name="aLocale">язык интерфейса "ru" или "en"</param>
/// <param name="aDocRecID">код докуента</param>
/// <param name="aTotalAmont">сумма доакмента</param>
/// <param name="aCurrencyRecID">код валюты 980-гривна</param>
/// <param name="aSessionID">код сессии System.Web.HttpContext.Current.Session.SessionID</param>
/// <returns></returns>
public static objects.objectEccGateway GetRequestFormFields(
objectCatalogPaymentSystemUPC aUPCParams,
string aLocale,
string aDocRecID,
double aTotalAmont,
int aCurrencyRecID,
string aSessionID
)
{
var obj = new tfoBookingUtils.PaymentSystem.UPC.objects.objectEccGateway()
{
Version = 1,
MerchantID = aUPCParams.MerchantId,
TerminalID = aUPCParams.TerminalId,
TotalAmount = (long)(aTotalAmont * 100),
Currency = aCurrencyRecID, //
Locale = aLocale,
OrderID = aDocRecID + "|" + DateTime.Now.ToString("yyMMddHHmmss"),
PurchaseTime = DateTime.Now.ToString("yyMMddHHmmss"),
Gateway = aUPCParams.Gateway,
SD = aSessionID,

PurchaseDesc = string.Format("Заказ {0} на сумму {1:N} грн.", aDocRecID, aTotalAmont)
};

string str = String.Format("{0};{1};{2};{3};{4};{5};{6};",
obj.MerchantID, obj.TerminalID, obj.PurchaseTime, obj.OrderID,
obj.Currency, obj.TotalAmount, obj.SD);
obj.Signature = RSACryptoUtils.RSASign(str, System.Web.HttpContext.Current.Server.MapPath(aUPCParams.CertificateFile));

return obj;
}
5. Готовим форму отправки запроса. отображаем поля формы во вьюшке

@model objectEccGateway;
...
<form action="@Model.Gateway" method="post" id="ecommerce_pay">
<input type="hidden" name="Version" value="@Model.Version" />
<input type="hidden" name="MerchantID" value="@Model.MerchantID" />
<input type="hidden" name="TerminalID" value="@Model.TerminalID" />
<input type="hidden" name="TotalAmount" value="@Model.TotalAmount" />
<input type="hidden" name="Currency" value="@Model.Currency" />
<input type="hidden" name="locale" value="@Model.Locale" />
<input type="hidden" name="SD" value="@Model.SD" />
<input type="hidden" name="OrderID" value="@Model.OrderID" />
<input type="hidden" name="PurchaseTime" value="@Model.PurchaseTime" />
<input type="hidden" name="PurchaseDesc" value="@Model.PurchaseDesc" />
<input type="hidden" name="Signature" value="@Model.Signature" />
<input type="submit" name="submit" value="Оплатить" />
</form>
...
6. Обрабтываем результат

В экшене-обработчике результата
пишеи примерно такое

ecc = new objectEccGateway()
{
MerchantID = Request.Params["MerchantID"],
OrderID = Request.Params["OrderID"],
//PurchaseTime = Convert.ToInt64(Request.Params["PurchaseTime"]),
SD = Request.Params["SD"],
TerminalID = Request.Params["TerminalID"],
ProxyPanResponse = Request.Params["ProxyPan"],
Currency = Convert.ToInt32(Request.Params["Currency"]),
ApprovalCode = Request.Params["ApprovalCode"],
Signature = Request.Params["Signature"],
Rrn = Convert.ToInt64(Request.Params["Rrn"]),
XID = Request.Params["XID"],
TranCode = Convert.ToInt32(Request.Params["TranCode"]),
TotalAmount = Convert.ToInt64(Request.Params["TotalAmount"])
};



if (Convert.ToInt32(Request.Params["TranCode"]) == 0)
{
//ok
}
else{
//error
}

Комментариев нет:

Отправить комментарий