📜 ⬆️ ⬇️

Direct entry to the 1C: Enterprise Directory via Linq on the example of working with Asp.Net users

Direct entry to the 1C: Enterprise Directory via Linq on the example of working with Asp.Net users


This article describes how to register a website user in the 1C: Enterprise 8 directory located in the MSSQL database. Further, the user can log in to the site using the login and password specified during registration. The work is conducted only with a reference book called Users and does not affect the system of working with users through the 1C configurator.

Only the simplest registration and authorization operations are described. Auxiliary operations for password recovery, informing via E-mail are not covered. Work is conducted by direct access to the MSSQL database through Linq. The approach allows you to use both the Asp.Net and 1C functionality at the same time, as well as do without intermediaries in the form of different CMS.


')

Creating a directory Users in 1C: Enterprise


It is assumed that the 1C information database is created and located on the MSSQL server in the local network or remotely at the hosting provider.

It is necessary through the configurator to create a directory Users with a code in the form of a string of 9 characters and the name of 25 characters.

Creating a directory Users in 1C: Enterprise

The structure of the fields is the following (the list of fields is taken in abundance for further functionality expansion):


The interface of the created directory is immediately accessible from 1C, which saves time on creating the administration interface. This is one of the advantages of the method when the whole arsenal of 1C: Enterprise tools is available. Other advantages include: deletion mark without physical deletion, filters and search, ability to build ACS queries, exchange with other 1C databases through data conversion, etc.

For example, the list of registered users is available immediately after defining the directory in the configurator:

A list of registered users is available immediately after defining the directory in the configurator

And also the user edit form:

User edit form interface

Setting up direct access to the MSSQL database



To access the data, you need to generate a cs file with LINQ definitions. To generate, you need to use the LinqTo1C utility, specifying which directories you need to unload, as well as the connection string to the MSSQL database. For our case, it is enough to unload only the Directory. Users.

Starting from version 1.2, LinqTo1C allows you to create a configuration file with the ability to change data. Despite the advantages of direct recording to the database, the method has disadvantages. For example, information recorded in this way will not be automatically registered in exchange plans. You yourself need to take care of maintaining the correctness of the data: generate a unique code, maintain integrity with other objects, check the newly entered data.

LinqTo1C utility

As a result of the utility, 2 files will appear: dbml - for visual presentation and cs-for adding to the C # project. It looks like this in the Visual Studio editor:

LinqTo1C Result in Visual Studio

Asp.Net code for registration and authorization


The code is for Asp.Net MVC, where AccountController is responsible for the user's work.

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); } 


Calls like FormsService.SignOut and FormsService.SignIn not so interesting as they are redirected to the standard methods: FormsAuthentication.SignOut and FormsAuthentication.SetAuthCookie .

The AccountMembershipService class accesses the MSSQL database.

To register a user, the CreateUser method is CreateUser . First, possible errors are checked: empty login, password, e-mail, duplicate login / e-mail, password match and password confirmation. Next, fill in the user field. The link is assigned a new Guid, the number is searched for as the maximum number + 1. The password is stored as a checksum in a closed one, the checksum is calculated from the user's password and a unique prefix that is stored here in the record.
 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; } 

For authorization, the ValidateUser method is used, which, after checking the parameters, checks the presence of the user in the database, the activity flag and tries to compare the checksum of the password with the calculated checksum of the transmitted password and the unique prefix.
  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(.); } } 

Source: https://habr.com/ru/post/210654/


All Articles