C#-скрипт автоматического приёма платежей на сайте ASP.NET

В данной статье я предоставлю такой долгожданный код реализации автоматического приема денежных средств на ASP.NET сайте.

Здесь я не буду приводить полного описания механизма подключения интернет-магазина к системе Web Money Merchant (для этого вы можете загрузить специальный видеоролик в моей рассылке на сайте http://skillcoding.com), а лишь остановлюсь на ключевых моментах, касающихся непосредственного перевода средств и последующей обработкой результатов транзакции.

Для осуществления приема оплаты на вашем сайте любого товара необходимо четко представлять от кого вы будете принимать оплату, за какой товар и каким образом будете доставлять покупку покупателю. Также не лишним будет задуматься над способом уведомления вас о результатах выполнения транзакции перевода средств и необходимости доставки товара клиенту.

Отсюда вытекают следующие задачи:

  1. Позволить  покупателю выбрать товар на сайте;
  2. Запросить контактные данные покупателя непосредственно перед переводом средств;
  3. Осуществить онлайн-транзакцию перевода средств – выполнить продажу товара.

1- и 2-й пункты довольно просты в реализации. Для этого необходимо просто создать специальную разметку на странице .aspx:

<formid=»mainForm»runat=»server»>

<asp:Panelrunat=»server»ID=»firstPanel»Visible=»true»>

<asp:TextBoxID=»TextBoxName»runat=»server»></asp:TextBox>

<asp:TextBoxID=»TextBoxPhone»runat=»server»></asp:TextBox>

<asp:ButtonID=»ButtonNextStep»runat=»server»Text=»Продолжить»

onclick=»ButtonNextStep_Click»/>

</asp:Panel>

<asp:PanelID=»secondPanel»runat=»server»Visible=»false»>

<asp:HiddenFieldID=»LMI_PAYEE_PURSE»runat=»server»
Value=»<%$ AppSettings:LMI_PAYEE_PURSE %>»/>

<asp:HiddenFieldID=»LMI_PAYMENT_AMOUNT»runat=»server»
Value=»<%$ AppSettings:LMI_PAYMENT_AMOUNT %>»/>

<asp:HiddenFieldID=»LMI_PAYMENT_DESC»runat=»server»
Value=»<%$ AppSettings:LMI_PAYMENT_DESC %>»/>

<asp:HiddenFieldID=»LMI_SIM_MODE»Visible=»false»runat=»server»
Value=»<%$ AppSettings:LMI_SIM_MODE %>»/>

<asp:HiddenFieldID=»HiddenFieldNAME»runat=»server»/>

<asp:HiddenFieldID=»HiddenFieldPHONE»runat=»server»/>

<asp:ButtonID=»GoToMerchant»runat=»server»
Text=»НачатьтранзакциюWebMoney»

PostBackUrl=»https://merchant.webmoney.ru/lmi/payment.asp»/>

</asp:Panel>

</form>

Пояснения.

На форме страницы имеется две панелиID=»firstPanel» и ID=»secondPanel». Изначально, при загрузке страницы отображается первая из них, вторая имеет свойство Visible=»false».

Первая панель ID=»firstPanel» содержит два текстовых поля для получения от покупателя его имени и номера телефона для последующего связывания с ним.

Также имеется кнопка ID=»ButtonNextStep», по нажатии на которой вызывается обработчик события ButtonNextStep_Click.

Код обработчика ButtonNextStep_Click:

protectedvoidButtonNextStep_Click(objectsender, EventArgse)

{

Panel1.Visible = false;

Panel2.Visible = true;

LabelName.Text = HiddenFieldNAME.Value = TextBoxName.Text;

LabelPhone.Text = HiddenFieldPHONE.Value = TextBoxPhone.Text;

}

Здесь, скрывается первая панель и отображается вторая панель, на которой пользователь в обычных лейблах наблюдает данные, введенные им на предыдущем шаге. Это сделано для того, что бы он лишний раз перепроверил свои данные перед совершением транзакции. Также, в этом методе устанавливаются значения дополнительных скрытых полей имени покупателя и его номера телефона, которые будут отправлены в мерчант.

Вторая форма содержит всего 6 скрытых полей (вместе с двумя дополнительными, определенными нами). Первые 4 из которых — стандартные и представляют для мерчанта служебную информацию, показывающую ему номер вашего кошелька для перевода на него средств, сумму перевода, описание товара (отображаемое название товара на странице мерчанта) и режим работы мерчанта (2 означает рабочий режим, также возможен и тестовый режим).

Первые 4 скрытых поля автоматически заполняются данными из web.config:

<appSettings>

<!—Параметры для WebMoney —>

<!—номер кошелька для приёма средств—>

<addkey=»LMI_PAYEE_PURSE»value=»R274925115943″/>

<!-суммаперевода—>

<addkey=»LMI_PAYMENT_AMOUNT»value=»30000.00″/>»/>
<!—описаниетовара—>

<addkey=»LMI_PAYMENT_DESC»value=»Мойтовар»/>
<!—2 – рабочийрежим—>

<addkey=»LMI_SIM_MODE»value=»2″/>

<!—ключ для формирования контрольной подписи—>

<addkey=»SECRETIAL_STRONG_KEY»                     value=»ladsjdfkljsao34589jket238wsw9lkd23f»/>

<!—/Параметры WebMoney—>

</appSettings>

Теперь все готово для начала отправки запроса на выполнение транзакции перевода средств.

Но, для фиксации оплаты, с целью дополнительной проверки валидности транзакции, необходимо в самом конце выполнения транзакции в мерчант отправить ответ для подтверждения/отклонения оплаты.

Зачем это? Это сделано для того, что если кто то попытается подменить сумму платежа, номер целевого кошелька, или предоставить другую лживую информацию для мерчанта, мы проверим эти данные и решим стоит ли принять покупку, или отклонить её.

Итак, какова схема этого.

Мы уже определились, что происходит по шагам:

  1. Пользователь загружает в браузер вашу страницу;
  2. Получив её, он заполняет текстовые поля имени и номера телефона;
  3. Нажимает на кнопку ButtonNextStep;
  4. Страница перезагружается и пользователь наблюдает на форме только что введенную собственную информацию. Также в скрытых полях уже находится служебная и пользовательская информация;
  5. Пользователь нажимает на кнопке GoToMerchant.

С этого момента пользователь попадает на страницу https://merchant.webmoney.ru/lmi/payment.asp.

Причем, на ту страницу также улетели данные из скрытых полей. Именно эти данные и будут играть ключевую роль на странице https://merchant.webmoney.ru/lmi/payment.aspдля перевода средств на ваш кошелек.

Но представьте, что между 4- и 5-м пунктами, пользователь изменил служебную информацию в скрытых полях?! К примеру, выставил значение суммы перевода в 0 условных единиц. Нажал на кнопку и успешно произвел покупку вашего товара за 0 долларов!!!

Что бы не позволить выполнять подобного рода махинации, сервис мерчанта перед зачисленим средств на ваш кошелёк подаст на ваш сайт последний запрос с данными транзакции для получения от вас ответа вроде «Да/НЕТ», мол транзакцию проводить, или нет.

В данном запросе мерчант посылает к нам некоторую служебную информацию (в том числе номер кошелька, сумму перевода, описание товара и т.д.). Мы проверяем єти данные и если они совпадают с начальными, то делаем вывод, что пользователь не пытался подменить информацию и ему можно позволить завершить транзакцию.

Вообще то мерчант дважды посылает запрос на ваш сайт. Первый раз он это делает перед началом проведения транзакции, а второй раз после транзакции.

Первый раз необходим для мерчанта при принятии решения о допустимости начинать транзакцию. Второй раз – для нас. Транзакция выполнена, средства переведены, но мерчант отправляет нам множественную служебную информацию, что бы мы уже сами решили что с ней делать и отправлять ли товар покупателю и т.д.

Итак, для обработки этих двух запросов воспользуемся обычным веб-хендлером .ashx:

<%@WebHandlerLanguage=»C#»Class=»Handler»%>

usingSystem;

usingSystem.IO;

usingSystem.Web;

usingSystem.Web.SessionState;

usingSystem.Collections.Generic;

usingSystem.Configuration;

usingSystem.Security.Cryptography;

usingSystem.Text;

publicclassHandler: IHttpHandler

{

publicvoidProcessRequest (HttpContextcontext)

{

//БЛОК ОБРАБОТКИ ФОРМЫ ПРЕДВАРИТЕЛЬНОГО ЗАПРОСА И ОТДАЧИ ОТВЕТА О           //ДАЛЬНЕЙШЕМ ВЫПОЛНЕНИИ ПЛАТЕЖА

stringLMI_PREREQUEST = context.Request.Form[«LMI_PREREQUEST»];
//Еслиэтоформапредварительногозапроса

if(«1″== LMI_PREREQUEST)

{

context.Response.ContentType = «text/plain»;

//Еслипроизошлаподмена суммы, или/и

//если произошла подмена целевого кошелька

if((context.Request.Form[«LMI_PAYMENT_AMOUNT»] !=                                ConfigurationManager.AppSettings[«LMI_PAYMENT_AMOUNT»]) ||

(context.Request.Form[«LMI_PAYEE_PURSE»] !=                                    ConfigurationManager.AppSettings[«LMI_PAYEE_PURSE»]))

{

//Отвечаем «NO»

context.Response.Write(«NO»);

return;

}

//Если все хорошо выводим «YES»

context.Response.Write(«YES»);

return;

}

//КОНЕЦ БЛОКА ОБРАБОТКИ ФОРМЫ ПРЕДВАРИТЕЛЬНОГО ЗАПРОСА И ОТДАЧИ             //ОТВЕТА О ДАЛЬНЕЙШЕМ ВЫПОЛНЕНИИ ПЛАТЕЖА

//БЛОК ОБРАБОТКИ ФОРМЫ ОПОВЕЩЕНИЯ О ВЫПОЛНЕННОМ ПЛАТЕЖЕ

//Если это форма оповещения о выполненном платеже

else

{

//БЛОК ФОРМИРОВАНИЯ ЦИФРОВОЙ ПОДПИСИ

//хеш подписи, сгенерированный на мерчанте

stringLMI_HASH = context.Request.Form[«LMI_HASH»];

//хеш подписи, генерируемый нами из полученных параметров

strings = context.Request.Form[«LMI_PAYEE_PURSE»] +

context.Request.Form[«LMI_PAYMENT_AMOUNT»] +

context.Request.Form[«LMI_PAYMENT_NO»] +

context.Request.Form[«LMI_MODE»] +

context.Request.Form[«LMI_SYS_INVS_NO»] +

context.Request.Form[«LMI_SYS_TRANS_NO»] +

context.Request.Form[«LMI_SYS_TRANS_DATE»] +

ConfigurationManager.AppSettings[«SECRETIAL_STRONG_KEY»] +

context.Request.Form[«LMI_PAYER_PURSE»] +

context.Request.Form[«LMI_PAYER_WM»];

stringhash = GetHashString(s);

//КОНЕЦ БЛОКА ФОРМИРОВАНИЯ ЦИФРОВОЙ ПОДПИСИ

//Вытягиваем детали клиента из переданной формы

String userNameAndPhone = context.Request.Form[«HiddenFieldNAME «].ToString() + context.Request.Form[«HiddenFieldNAME»].ToString();

//проверяем совпадение цифровой подписи
if(string.Compare(LMI_HASH, hash, true) != 0)

{

userNameAndPhone= «Товар «+ userNameAndPhone+ «НЕ отправлять – попытка мошенничества!»;

}

//здесь можно отправить письмо нам с текстом, содержащим значение // из userNameAndPhone, можно записать текстовый файл с данными
//пользователя, можно занести информацию в БД и т.д.

}

privatestaticstringGetHashString(strings)

{

//…
//выполняем преобразование входной строки в хеш-значение

returnresultInHASH;

}

publicboolIsReusable

{

get

{

returnfalse;

}

}

}

Файл большой, но очень простой. Суть в следующем.

Если от мерчанта пришел параметр LMI_PREREQUEST равным 1, значит, это предварительный запрос. В этом случае достаточно проверить сумму перевода и целевой кошелек (то есть наш ли это кошель).

Если же пришла не 1, а другое значение, значит, перевод выполнен уже и нам осталось для себя определить последние решения относительно дальнейших наших действий. Еще раз напомню, что в этот момент оплата уже выполнена и мерчант поставил себе «плюсик» об удачно завершенной транзакции. Все, что происходит после этого, касается только нас.

Итак, к примеру, пришло значение не 1.

Вместе с ним приходит много других параметров, которые просто предоставляют информацию о проведенной транзакции (время транзакции, кошелек покупателя, номер транзакции в системе Web Money …), а также главный параметр LMI_HASH.

Последний содержит в себе хеш-значение склеинных воедино значений по порядку:

  1. LMI_PAYEE_PURSE;
  2. LMI_PAYMENT_AMOUNT;
  3. LMI_PAYMENT_NO;
  4. LMI_MODE;
  5. LMI_SYS_INVS_NO;
  6. LMI_SYS_TRANS_NO;
  7. LMI_SYS_TRANS_DATE;
  1. WEBMONRY_SECRET_KEY;
  1. LMI_PAYER_PURSE;
    10. LMI_PAYER_WM.

1-7 и 9-10 параметры на мерчанте формируются по завершению транзакции и отправки в наш .ashx-хендлер. 8-й параметр хранится в настройках вашего аккаунта на мерчанте постоянно, а также в вашем web.config.

Соответственно, мы у себя также «лепим» такую же строку s из тех же параметров, но на восьмом месте подставляем ключ из web.config (понятно, что значение SECRETIAL_STRONG_KEYи его эквивалент в аккаунте мерчанта должны совпадать).

После этого сравниваем оба значения на равенствоif(string.Compare(LMI_HASH, hash, true) != 0)

И если все впорядке, то просто что-то выполняем с информацией о пользователе, если же есть несоответствия, то выполняем дополнительные действия, или вовсе что-то не выполняем. Это уже на ваше усмотрение.

Ах да, забыл, метод GetHashString(strings) вы можете реализовать сами. Он просто принимает некоторый строковый литерал и возвращает его хеш-код, используя любой алгоритм. Главное, заранее знать каким алгоритмом будете пользоваться, ведь в аккаунте мерчанта также необходимо указать такой же алгоритм для получения хеш-подписи.

Вот и все относительно сердца онлайн оплат. Конечно, кроме кода, приведенного в данной статье, должно присутствовать еще много всего дополнительного, но это остальное призвано улучшить и оптимизировать работу того кода, что рассмотрели здесь.

За более подробной и детальной информацией относительно написания сриптов интернет-магазинов по работе с ситемами WebMoney, RBK Money, Z-Payment, PayPalи другие обращайтесь на мой сайт http://skillcoding.comв раздел ASP.NET и/или подписавшись на рассылку, где многие инструкции представлены в подробных видеоруководствах.

Автор: Александр Гудок.