Подключение Яндекс-Денег в ASP.NET MVC

Последнее обновление: 1.11.2015

При создании продающего сайта, например, интернет-магазина, в определенный момент мы сталкиваемся с подключением различных форм оплаты на сайт. На мой взгляд самой простой из всех форм оплаты являются Яндекс Деньги, которые предоставляют нам возможность оплаты с помощью счета в яндекс-деньгах или с помощью карт Visa и MasterCard. Правда, оплата доступна только на другой счет в тех же яндекс-деньгах. Рассмотрим, как подключить подобную функциональность в ASP.NET MVC 5.

Яндекс Деньги предоставляет разные возможности для оплаты. Все они подразумевают создание платежной формы, которая по нажатию кнопки отправляется на сервис яндекса, где клиент и производит непосредственно оплату. И после оплаты пользователя переадресует на определенный адрес. В случае успешного платежа мы можем получить уведомления по почте или по HTTP, в зависимости от выбранных параметров, обработать эти уведомления и произвести определенные действия, например, отправить купленный товар клиенту.

Рассмотрим пример с HTTP-уведомлениями. HTTP-уведомления позволят сразу же после факта оплаты обработать платеж у себя на сервере. Вся сопровадительная документация доступна на сайте яндекс: https://tech.yandex.ru/money/doc/dg/reference/notification-p2p-incoming-docpage/

Первым делом необходимо подключить HTTP-уведомления. Это можно сделать в личном кабинете по адресу https://sp-money.yandex.ru/myservices/online.xml:

Оплата с карт Visa и MasterCard и Янндекс Деньги в ASP.NET MVC

Во-первых, в поле адреса нам надо ввести адрес того ресурса, который будет обрабатывать приходящие от Яндекса уведомления об оплате. На данный момент у нас ничего нет, но потом можно изменить. Только не надо устанавливать адреса типа localhost:xxxx. Нужен не локальный адрес, доступный извне. Запросы будут отправляться с помощью http-метода POST.

Во-вторых, яндекс нам дает некоторое секретное слово, которое мы можем посмотреть, нажав на кнопку "Показать секрет". Оно нам понадобится для проверки уведомлений в целях безопасности.

И в третьих, нужно установить отметку в поле "Отправлять уведомления"

Теперь создадим само приложение. Мы не будем создавать полноценное приложение типа интернет-магазина, а только сосредоточимся на непосредственно функционале оплаты.

Пусть у нас в приложении есть модель Order, которая описывает сделанный пользователем заказ:

public class Order
{
    public string Id { get; set; } // id заказа
    public DateTime? Date { get; set; } // дата
    public decimal Sum { get; set; } // сумма заказа
    public string Sender { get; set; } // отправитель - кошелек в ЯД
    public string Operation_Id { get; set; } // id операции в ЯД
    public decimal? Amount { get; set; } // сумма, которую заплатали с учетом комиссии
    public decimal? WithdrawAmount { get; set; } // сумма, которую заплатали без учета комиссии
    public int? UserId { get; set; } // id пользователя в системе, который сделал заказ
}

Яндекс передает нам не только сумму платежа, которая попала на наш счет, но и сумму, без учета комиссии. Это позволяет нам отследить, сколько же действительно заплатил клиент.

Данные о заказах лежат в базе данных и обслуживаются следующим контекстом данных:

public class StoreContext : DbContext
{
    public StoreContext() : base("DefaultConnection")
    {
	}
    public DbSet<Order> Orders { get; set; }
}

Вначале определим форму, которая будет передаваться на сервер яндекса. Для этого создадим промежуточную модель

public class OrderModel
{
    public string OrderId { get; set; }
    public decimal Sum { get; set; }
}

Она будет передавать из контроллера в представление id заказа и сумму для оплаты. Определим в контроллере простой метод:

StoreContext db = new StoreContext();
public ActionResult Index()
{
    Order order = db.Orders.FirstOrDefault();
	if(order!=null)
	{
		OrderModel orderModel = new OrderModel { OrderId = order.Id, Sum = order.Sum };
        return View(orderModel);
	}
	return HttpNotFound();	
}

В данном случае для теста будем оплачивать первый попавшийся заказ. И создадим представления для вывода формы с информацией о заказе:

@model YandexPaymentApp.Models.OrderModel
@{
    ViewBag.Title = "Страница оплаты";
}
<h2>Оплата товара @Model.OrderId</h2>
<div>
    <form method="POST" action="https://money.yandex.ru/quickpay/confirm.xml">
        <input name="label" value="@Model.OrderId" type="hidden">
        <input name="receiver" value="410011174743222" type="hidden">
        <input name="quickpay-form" value="shop" type="hidden">
        <input type="hidden" name="targets" value="Оплата заказа @Model.OrderId">
        <label for="sum">Сумма: </label><br />
        <input name="sum" value="@Model.Sum" maxlength="10" data-type="number" type="text"><br /><br />
        <label for="sum">Способ оплаты: </label><br />
        <input type="radio" name="paymentType" value="PC">Яндекс.Деньгами
        <input type="radio" name="paymentType" value="AC">Банковской картой<br /><br />
        <input type="submit" name="submit-button" value="Оплатить">
        <input name="successURL" value="http://mystore.somee.com/Home/Paid" type="hidden">
        <input name="quickpay-back-url" value="http://mystore.somee.com/" type="hidden">
    </form>
</div>

Для отправки формы нам надо указать на форме ряд параметров. Параметр receiver указывает кошелек в ЯД, на который клиент будет переводить деньги. То есть если мы сами являемся продавцом, то указываем здесь свой кошелек.

Поле label (<input name="label" value="@Model.OrderId" type="hidden">) выступает в качестве идентификатора платежа в нашей системе. Таким идентификатором является Id заказа.

Параметр quickpay-form указывает на тип платежей, в нашем случае он имеет значение "shop".

Параметр targets содержит название платежа, которое будет отображаться клиенту при оплате.

Параметр sum указывает на сумму, которую вводит клиент.

Две радиокнопки позволяют нам задать тип платежа: через кошелек ЯД или с помощью карт.

Параметр successURL указывает на ресурс, на который будет переадресация после успешной оплаты. Здесь задан тот же адрес, что указывался выше для получения http-уведомления. Однако в данном случае редирект будет идити с помощью запроса GET, то есть два метода будут обрабатывать разные типы запросов, хотя и будут называться одинаково.

Для параметра successURL мы можем задать следующий метод:

[HttpGet]
public string Paid()
{   
    return "<p>заказ оплачен</p>";
}

В рамках примера я сделал рочень простой метод, который просто уведомляет, что оплата произведена.

Теперь самое интересное - добавим метод, который и будет обрабатывать полученные HTTP-уведомления о платеже:

[HttpPost]
public void Paid(string notification_type, string operation_id, string label, string datetime, 
        decimal amount, decimal withdraw_amount, string sender, string sha1_hash, string currency, bool codepro)
{
    string key = "xxxxxxxxxxxxxxxx"; // секретный код
    // проверяем хэш
    string paramString = String.Format("{0}&{1}&{2}&{3}&{4}&{5}&{6}&{7}&{8}",
        notification_type, operation_id, amount, currency, datetime , sender, 
		codepro.ToString().ToLower(), key, label);
    string paramStringHash1 = GetHash(paramString);
    // создаем класс для сравнения строк
    StringComparer comparer = StringComparer.OrdinalIgnoreCase;
	// если хэши идентичны, добавляем данные о заказе в бд
    if (0 == comparer.Compare(paramStringHash1, sha1_hash))
    {
		Order order = db.Orders.FirstOrDefault(o => o.Id == label);
        order.Operation_Id = operation_id;
        order.Date = DateTime.Now;
        order.Amount = amount;
        order.WithdrawAmount = withdraw_amount;
        order.Sender = sender;
        db.Entry(order).State = EntityState.Modified;
        db.SaveChanges();
    }
}
public string GetHash(string val)
{
    SHA1 sha = new SHA1CryptoServiceProvider();
    byte[] data = sha.ComputeHash(Encoding.Default.GetBytes(val));
			
    StringBuilder sBuilder = new StringBuilder();

    for (int i = 0; i < data.Length; i++)
    {
        sBuilder.Append(data[i].ToString("x2"));
    }
	return sBuilder.ToString();       
}

От яндекса в http-уведомлении мы получаем ряд параметров о платеже. Однако есть одна проблема: этому же методу может обратиться любой и послать какие угодно параметры. Для этого нам и нужно секретное слово. Оно указывается в качестве значения строковой переменной key. Оно позволяет сгенерировать хэш пароля с использованием алгоритма sha1. Затем мы сравниваем оба хэша, и если они равны, то данные добавляем в бд.

Для генерации хэша значения параметров определен дополнительный метод GetHash.

Разместим приложение на внешнем хостинге. Обратимся к нему:

Яндекс Деньги в ASP.NET MVC 5

Введем сумму, выберем метод оплаты, и нас перебросит на форму оплаты в яндекс-деньгах.

После успешной оплаты клиента переадресует на метод Home/Paid, обрабатывающего запрос Get. А на метод Home/Paid, обрабатывающий запрос POST, будет отправлено http-уведомление.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850