Прямая запись в справочник 1C: Предприятие через Linq на примере работы с пользователями Asp.Net
Статья описывает как зарегистрировать пользователя веб-сайта в справочнике 1С: Предприятие 8, расположенном в MSSQL базе данных. Далее пользователь может авторизоваться на сайте, используя логин и пароль, указанный при регистрации. Работа ведется только со справочником с названием Пользователи и не затрагивает систему работы с пользователями через конфигуратор 1С.
Описаны только простейшие операции по регистрации и авторизации. Вспомогательные операции по восстановлению пароля, информированию через E-mail не освещаются. Работа ведется прямым доступом к базе MSSQL через Linq. Подход позволяет использовать одновременно функционал Asp.Net и 1С, а также обойтись без посредников в виде разных CMS.
Создание справочника Пользователи в 1С: Предприятие
Предполагается, что информационная база 1С создана и расположена на MSSQL-сервере в локальной сети или удаленно у
Необходимо через конфигуратор создать справочник Пользователи с кодом в виде строки 9 символов и наименованием 25 символов.
Структура полей следующая (перечень полей взят с избытком для дальнейшего расширения функциональности):
- Активный: Булево
- ДатаРегистрации: Дата
- Email: Строка 255, переменная
- Пароль: Строка 32 переменная
- ПарольПрефикс: Строка 16 переменная
- Язык: Строка 255 переменная
- ФорматДаты: Строка 20 переменная
- КодАктивации: Строка 36 переменная
- КодВосстановленияПароля: Строка 36 переменная
- ДатаАктивности: Дата
Интерфейс созданного справочника сразу доступен из 1С, что позволяет сэкономить время на создании интерфейса администрирования. Это одно из достоинств способа, когда доступен весь арсенал средств 1С: Предприятие. К другим достоинствам можно отнести: пометка на удаление без физического удаления, фильтры и поиск, возможность построения запросов СКД, обмен с другими базами 1С через конвертацию данных и т.д.
Например, доступен список зарегистрированных пользователей сразу после определения справочника в конфигураторе:
А также форма редактирования пользователя:
Настройка прямого доступа к базе данных MSSQL
Для доступа к данным нужно сгенерировать файл cs с определениями LINQ. Для генерации нужно воспользоваться утилитой LinqTo1C, указав какие справочники нужно выгружать, а также строку подключения к MSSQL базе данных. Для нашего случая достаточно выгрузить только Справочник.Пользователи.
Начиная с версии 1.2, LinqTo1C позволяет создавать конфигурационный файл с возможностью изменения данных. Не смотря на достоинства прямой записи в базу данных, у способа есть недостатки. Например, записанная таким способом информация не будет автоматически зарегистрирована в планах обмена. Вам самостоятельно нужно заботиться о поддержании правильности данных: генерировать уникальный код, поддерживать целостность с другими объектами, проверять вновь вносимые данные.
В результате работы утилиты появятся 2 файла: dbml – для визуального представления и cs-для добавления в проект C#. Выглядит в редакторе Visual Studio это так:
Asp.Net код для регистрации и авторизации
Код приведен для Asp.Net MVC, где за работу пользователя отвечает AccountController.
AccountController:
public ActionResult LogOn()
{
ViewBag.Title = Resources.Account.LogonTitle;
return View("~/Views/Dotnet/Logon.cshtml");
}
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Dotnet");
}
}
else
{
ModelState.AddModelError("", "");
}
}
// If we got this far, something failed, redisplay form
return View("~/Views/Dotnet/Logon.cshtml", model);
}
public ActionResult LogOff()
{
FormsService.SignOut();
return RedirectToAction("Index", "Dotnet");
}
public ActionResult Register()
{
ViewBag.Title = Resources.Account.RegisterTitle;
ViewBag.PasswordLength = MembershipService.MinPasswordLength;
return View("~/Views/Dotnet/Register.cshtml");
}
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus = MembershipService.CreateUser(model.UserName, model.Email, model.Password, model.ConfirmPassword);
if (createStatus == MembershipCreateStatus.Success)
{
FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
return RedirectToAction("Index", "Dotnet");
}
else
{
ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
ViewBag.PasswordLength = MembershipService.MinPasswordLength;
return View("~/Views/Dotnet/Register.cshtml", model);
}
Вызовы вида FormsService.SignOut
и FormsService.SignIn
не такие интересные, так как они перенаправляются к стандартным методам: FormsAuthentication.SignOut
и FormsAuthentication.SetAuthCookie
.
Класс AccountMembershipService
осуществляет обращение к базе MSSQL.
Для регистрации пользователя предназначен метод CreateUser
. Сначала проверяются возможные ошибки: пустой логин, пароль, e-mail, дублирующийся логин/e-mail, совпадение пароля и подтверждение пароля. Далее заполняются поля пользователя. Ссылке присваивается новый Guid, номер ищется как максимальный номер + 1. Пароль хранится в виде контрольной суммы в закрытом, контрольная сумма вычисляется от пароля пользователя и уникального префикса, который хранится здесь же в записи.
public MembershipCreateStatus CreateUser(string userName, string email, string password, string confirmPassword)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password");
if (String.IsNullOrEmpty(email)) throw new ArgumentException("Value cannot be null or empty.", "email");
MembershipCreateStatus status = MembershipCreateStatus.ProviderError;
using (var dataContext = new ElisyCMS(ConfigurationManager.ConnectionStrings["ElisyCMS"].ConnectionString))
{
if (dataContext.СправочникПользователи.Where(m => m.Наименование == userName && m.ПометкаУдаления == new Binary(new byte[]{0})).Count() != 0)
return MembershipCreateStatus.DuplicateUserName;
if (dataContext.СправочникПользователи.Where(m => m.Email == email && m.ПометкаУдаления == new Binary(new byte[] { 0 })).Count() != 0)
return MembershipCreateStatus.DuplicateEmail;
if (password != confirmPassword)
return MembershipCreateStatus.InvalidPassword;
try
{
СправочникПользователи user = new СправочникПользователи();
user.Ссылка = Guid.NewGuid().ToByteArray();
user.ПометкаУдаления = new byte[] { 0 };
user.Предопределенный = new byte[] { 0 };
var codeRequest = from a in dataContext.СправочникПользователи
where Convert.ToInt32(a.Код) > 0
orderby Convert.ToInt32(a.Код) descending
select Convert.ToInt32(a.Код);
var lastCode = codeRequest.Take(1).FirstOrDefault();
user.Код = (lastCode + 1).ToString().PadLeft(9, '0');
user.Наименование = userName;
byte[] saltBytes = new byte[8];
new RNGCryptoServiceProvider().GetBytes(saltBytes);
user.ПарольПрефикс = Convert.ToBase64String(saltBytes);
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(user.ПарольПрефикс + password);
byte[] hash = new SHA1CryptoServiceProvider().ComputeHash(passwordBytes);
user.Пароль = Convert.ToBase64String(hash);
user.ДатаРегистрации = DateTime.Now;
user.ДатаАктивности = DateTime.Now;
user.Активный = new Binary(new byte[] { 1 });
user.Язык = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
//user.КодАктивации = Guid.NewGuid().ToString();
user.Email = email;
dataContext.СправочникПользователи.InsertOnSubmit(user);
dataContext.SubmitChanges();
return MembershipCreateStatus.Success;
}
catch (Exception ex)
{
return MembershipCreateStatus.ProviderError;
}
}
return status;
}
Для авторизации предназначен метод ValidateUser, который после проверки параметров проверяет наличие пользователя в базе, флаг активности и пытается сравнить контрольную сумму пароля с вычисленной контрольной суммой переданного пароля и уникального префикса.
public bool ValidateUser(string userName, string password)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password");
using (var dataContext = new ElisyCMS(ConfigurationManager.ConnectionStrings["ElisyCMS"].ConnectionString))
{
var пользователь = dataContext.СправочникПользователи.Where(m => m.Наименование.ToUpper() == userName.ToUpper()).FirstOrDefault();
if (пользователь == null)
return false;
if (пользователь.Активный.ToArray()[0] == 0)
return false;
if (String.IsNullOrWhiteSpace(пользователь.Пароль))
return true;
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(пользователь.ПарольПрефикс + password);
byte[] hash = new SHA1CryptoServiceProvider().ComputeHash(passwordBytes);
return Convert.ToBase64String(hash).Equals(пользователь.Пароль);
}
}
Автор: Elisy