Прямая запись в справочник 1C: Предприятие через Linq на примере работы с пользователями Asp.Net

от автора

Прямая запись в справочник 1C: Предприятие через Linq на примере работы с пользователями Asp.Net

Статья описывает как зарегистрировать пользователя веб-сайта в справочнике 1С: Предприятие 8, расположенном в MSSQL базе данных. Далее пользователь может авторизоваться на сайте, используя логин и пароль, указанный при регистрации. Работа ведется только со справочником с названием Пользователи и не затрагивает систему работы с пользователями через конфигуратор 1С.

Описаны только простейшие операции по регистрации и авторизации. Вспомогательные операции по восстановлению пароля, информированию через E-mail не освещаются. Работа ведется прямым доступом к базе MSSQL через Linq. Подход позволяет использовать одновременно функционал Asp.Net и 1С, а также обойтись без посредников в виде разных CMS.

Создание справочника Пользователи в 1С: Предприятие

Предполагается, что информационная база 1С создана и расположена на MSSQL-сервере в локальной сети или удаленно у хостинг-провайдера.

Необходимо через конфигуратор создать справочник Пользователи с кодом в виде строки 9 символов и наименованием 25 символов.

Создание справочника Пользователи в 1С:Предприятие

Структура полей следующая (перечень полей взят с избытком для дальнейшего расширения функциональности):

  • Активный: Булево
  • ДатаРегистрации: Дата
  • Email: Строка 255, переменная
  • Пароль: Строка 32 переменная
  • ПарольПрефикс: Строка 16 переменная
  • Язык: Строка 255 переменная
  • ФорматДаты: Строка 20 переменная
  • КодАктивации: Строка 36 переменная
  • КодВосстановленияПароля: Строка 36 переменная
  • ДатаАктивности: Дата

Интерфейс созданного справочника сразу доступен из 1С, что позволяет сэкономить время на создании интерфейса администрирования. Это одно из достоинств способа, когда доступен весь арсенал средств 1С: Предприятие. К другим достоинствам можно отнести: пометка на удаление без физического удаления, фильтры и поиск, возможность построения запросов СКД, обмен с другими базами 1С через конвертацию данных и т.д.

Например, доступен список зарегистрированных пользователей сразу после определения справочника в конфигураторе:

Доступен список зарегистрированных пользователей сразу после определения справочника в конфигураторе

А также форма редактирования пользователя:

Интерфейс формы редактирования пользователя

Настройка прямого доступа к базе данных MSSQL

Для доступа к данным нужно сгенерировать файл cs с определениями LINQ. Для генерации нужно воспользоваться утилитой LinqTo1C, указав какие справочники нужно выгружать, а также строку подключения к MSSQL базе данных. Для нашего случая достаточно выгрузить только Справочник.Пользователи.

Начиная с версии 1.2, LinqTo1C позволяет создавать конфигурационный файл с возможностью изменения данных. Не смотря на достоинства прямой записи в базу данных, у способа есть недостатки. Например, записанная таким способом информация не будет автоматически зарегистрирована в планах обмена. Вам самостоятельно нужно заботиться о поддержании правильности данных: генерировать уникальный код, поддерживать целостность с другими объектами, проверять вновь вносимые данные.

Утилита LinqTo1C

В результате работы утилиты появятся 2 файла: dbml – для визуального представления и cs-для добавления в проект C#. Выглядит в редакторе Visual Studio это так:

Результат работы LinqTo1C в 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(пользователь.Пароль);             }         } 

ссылка на оригинал статьи http://habrahabr.ru/post/210654/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *