Авторизация на Delphi — это одна из интереснейшим тем программирования. Что вообще представляет из себя процесс авторизации?
Авторизация пользователя — это процесс подтверждения его личности для предоставления доступа к определенным ресурсам или функциям. В настоящее время существует множество методов авторизации, каждый из которых имеет свои преимущества и недостатки.
Виды авторизации пользователей
Можно выделить основные существующие способы авторизации пользователей в программах:
- Логин и пароль — классический метод авторизации, который используется во многих сервисах. Он прост в использовании и обеспечивает высокую степень безопасности, если пароли хранятся правильно. Однако, многие пользователи испытывают сложности с запоминанием паролей и предпочитают использовать альтернативные методы.
- Двухфакторная авторизация — это метод, при котором пользователь должен ввести не только логин и пароль, но и дополнительный код, полученный на телефон или электронную почту. Этот метод обеспечивает более высокий уровень безопасности, так как даже если злоумышленник узнает пароль пользователя, без доступа к дополнительному коду он не сможет войти в аккаунт.
- Биометрическая авторизация — использование отпечатков пальцев, сетчатки глаза или голоса для идентификации пользователя. Этот метод быстрый и удобный, однако он может быть менее безопасным, особенно если биометрические данные хранятся на сервере в незашифрованном виде.
- OAuth 2.
В этом посте мы рассмотрим классический метод авторизации пользователей. Очевидно, что для создания формы авторизации пользователя следует воспользоваться обычной формой.
Форма авторизации пользователя
В основном все приложения создаются по одному из двух типов: многодокументное (MDI) и однодокументное (SDI). Создание формы авторизации и ее взаимодействие с программой мы рассмотрим на примере многодокументного типа приложения. Авторизация пользователя в однодокументном приложении происходит совершенно аналогично.
Создать форму авторизации можно двумя способами. Можно сделать так, что она будет появляться в самом начале перед загрузкой главной формы приложения:

А можно сделать так, что окно авторизации (форма) будет загружено как модальное вместе с главной формой приложения:

В данном случае создание формы авторизации на Delphi осуществляется уже внутри главного окна приложения. В этом случае мы прячем меню и другие элементы управления и показываем их тем пользователям, которые будут иметь доступ к соответствующим пунктам меню и элементам управления. Ну, например, если вход был осуществлен под администратором, то ему доступны все пункты меню, если под другим пользователем, то какие-то пункты из меню для него остаются невидимыми.
Давайте рассмотрим первый случай, когда форма авторизации пользователя появляется без главного окна приложения.
В главной форме приложения (MDI-форме) следует написать следующий код:
procedure TfrmMDI.FormCreate(Sender: TObject); var iniF: TIniFile; sServer, sPort, sUser, sPassword, sConnection: string;//Строка соединения с БД. begin sTekPapka:=getcurrentdir; try frmMDI.AlphaBlendValue:=0; //Прячем главную форму (делаем ее полностью прозрачной) ADOConnection1.Close;//Закрываем соединение с БД //Считываем данные из файла Конфиг. //Для этого создаем объект файла Конфиг iniF:=TiniFile.Create(STekPapka+'\Config.ini'); //Считываем содержимое файла Конфиг и заносим значения в форму sServer:=iniF.ReadString('DB', 'Server',''); sPort:=iniF.ReadString('DB', 'Port',''); sUser:=iniF.ReadString('DB', 'User',''); sPassword:=iniF.ReadString('DB', 'Password',''); iniF.free; sConnection:='Provider=MSDASQL.1;Persist Security Info=False;Extended Properties="Driver=MySQL ODBC 8.0 Unicode Driver;SERVER='+sServer+';UID='+sUser+';password='+sPassword+';DATABASE=bus_station;PORT='+sPort+';charset=cp1251;COLUMN_SIZE_S32=1"'; ADOConnection1.ConnectionString:=sConnection; ADOConnection1.Open; // Открываем соединение except Application.CreateForm(TfrmConnection,frmConnection); frmConnection.Show; end; end;
Давайте разберем этот код... Секция var содержит объявления переменных двух типов. Один тип TIniFile. Другой String.
var iniF: TIniFile; sServer, sPort, sUser, sPassword, sConnection: string;//Строка соединения с БД.
Я использую тип TIniFile для хранения данных о подключении и параметрах программы в INI-файле. Это является несколько устаревшим подходом, но он прост, понятен и до сих пор активно используется в виду того, что с помощью него можно хранить любые параметры настроек. Мне так же нравится этот подход.
В данном случае этот тип данных я использую для того, чтобы считать информацию о подключении к базе данных с INI-файла. Ну то есть, каждый раз, когда мы запускаем программу, она осуществляет подключение к базе данных. Для подключения к ней используется множество параметров, в числе которых номер порта, адрес сервера, на котором расположена база данных, имя пользователя базы данных (не путать с пользователем программы, который авторизуется), пароль подключения к базе данных (не путать с паролем входа в программу пользователя при авторизации).
Могут еще храниться разные параметры подключения, но перечисленные являются основными. И чтобы каждый раз при запуске программы не вводить их, удобно было бы хранить их в конфигурационном INI файле, так и назвав его, например, Config.ini.
Переменные sServer, sPort, sUser, sPassword будут содержать значения этих самых параметров подключения, которые будут считаны с Config.ini и присвоены нашим переменным.
Содержимое Config.ini может выглядеть следующим образом:
[ORG] NumberParking=1 NameOrg=ЗАО "Парковка" FIORuk=Маковозов Михаил Арсеньевич DolRuk=Директор FIOGlBuh=Михайлова Дарья Александровна INN=3123351893 KPP=332901001 BANK=Отделения и филиалы Сбербанка в г. Белогорода. Дополнительный офис № 8627/01357 RS=40703810777020000308 KS=30101810100000000612 BIK=042908612 UrAdres=308001, г. Белгород, ул. Вокзальная, 33а. PostAdres=308001, г. Белгород, ул. Вокзальная, 33а. OGRN=1105543026445 OKVD=18.1 Telefon=+7 (4722) 32-14-96, +7 (4722) 40-23-54 Website=https://belparking.ru [DB] Server=localhost Port=3306 User=root Password=1234
Данный файл состоит из секций. В данном случае у меня их всего две: [ORG] и [DB].
Эти секции служат для группировки данных файла (для удобства восприятия). Как видите, в секции [ORG] я храню информацию об организации, а в секции [DB] я храню информацию о подключении к базе данных. Конечно название секций и способ хранения — условны. Например, информацию об организации удобно хранить не в таком файле, а в самой базе данных, поскольку при многопользовательском доступе такой Config.ini в отношении реквизитов организации придется настраивать ан каждом компьютере, а это не удобно. Но все же мы оставим этот вопрос, ведь здесь мы рассматриваем гипотетический пример.
Итак, идем дальше. У нас есть еще одна переменная sConnection. Она будет содержать в себе строку подключения. Еще одной важной переменной, которая будет глобальной является sTekPapka. Она будет содержать в себе путь к каталогу, из которого мы запустили нашу программу. То есть, текущий каталог программы. Ее следует объявить в модуле главной формы приложения в секции для объявления глобальных переменных.
Далее мы получаем наш текущий каталог и для того, чтобы показать отдельно нашу форму авторизации без главного окна приложения, мы просто делаем полную прозрачность нашему главному окну посредством установки свойства frmMDI.AlphaBlendValue:=0.
Отлично. Теперь, на всякий случай, закрываем соединение, считываем наши параметры подключения из файла Config.ini и присваиваем их нашим описанным выше переменным. А затем в переменной sConnection мы объединяем все это в одну строку подключения к базе данных.
В данном случае, в качестве базы данных у меня используется база с именем bus_station. У вас будет свое имя базы данных. О том, как подключиться к базе данных я рассказываю в своей статье Подключение к базе данных в Delphi.
Затем мы присваиваем нашу сформированную строку подключения свойству ConnectionString объекта adoConnection и открываем наше соединение.
В примере я использую технологию ADO, поэтому использую объект соединения с базой данных adoConnection. Вы также можете использовать аналогичные объекты из других библиотек. Затем соединение открывается.
Если же при подключении к базе данных возникает ошибка, мы выводим форму, сообщающую пользователю о том, что подключение не состоялось, либо, как у меня в промере, форму для того, чтобы указать параметры подключения. В данном случае в этой форме при ее создании можно также считать эти параметры подключения из файла Config.ini.
except Application.CreateForm(TfrmConnection,frmConnection); frmConnection.Show; end;
Например, это может выглядеть вот так:

В данном случае пользователю нужно изменить данные, нажать сохранить и перезапустить программу.
Поехали дальше... А дальше мы пишем в главной форме приложения в событии onShow такой код:
procedure TfrmMDI.FormShow(Sender: TObject); begin //Создаем форму авторизации Application.CreateForm(TfrmLogin,frmLogin); frmLogin.Show; end;
Форма авторизации Delphi в данном случае у нас будет называться frmLogin. И мы пишем в ней вот такой код:
Uses .....System.SysUtils, System.TypInfo.....;//Добавляем два модуля к существующим. type TStrings = (Администраторы, Логисты, Кассиры);//Объявляем свой тип ... //Объявляется класс формы ... procedure TfrmLogin.FormCreate(Sender: TObject); var KolZap: integer; TekZap: integer; i: integer; // Счетчик begin //Прячем все пункты меню из главной формы приложения frmMDI.mnuAdmin.Visible:=false; frmMDI.mnuLogin.Visible:=false; frmMDI.mnuExit.Visible:=false; //Подключаемся к Таблице Логины adoLogin.Open; //Заполняем логинами раскрывающийся список cboLogin.Clear; KolZap:=adoLogin.RecordCount; adoLogin.First; TekZap:=adoLogin.RecNo; for i:=TekZap to KolZap do begin cboLogin.Items.Add(adoLogin.fieldbyname('Логин').AsString); adoLogin.Next; end; //Сортируем список cboLogin.Sorted:=true; //Ставим первое значение в спиcке по умолчанию cboLogin.ItemIndex:=0; end;
В данном случае, смотрите. Я люблю сразу создавать для себя типы пользователей и хранить их в отдельной таблице в базе данных. Также я создаю для них отдельный тип данных, который после использую для проверки того, какой тип пользователя сделал вход в систему.
На форме есть две кнопки Вход и Отмена. На кнопке Вход в событии onClick пишем следующий код:
procedure TfrmLogin.cmdInputClick(Sender: TObject); var sTiplist: TStrings; sPassword: string; begin sLogin:=cboLogin.Text;//Выбранный из списка логин sPassword:=trim(txtPassword.Text);//Введенный пользователем пароль //Теперь проверяем пароль, который ввел пользователь adoLogin.First;//Ставим указатель на первую запись таблицы adoLogin.Locate('Логин', sLogin,[]);// Находим в таблице запись с выбранным логином if adoLogin.fieldbyname('Пароль').AsString = sPassword then //Если пароль совпадает с введенным, то begin sTipUser:=StringReplace(adoLogin.fieldbyname('Тип').AsString, ' ', '_',[rfReplaceAll, rfIgnoreCase]); sTiplist:=TStrings(GetEnumValue(TypeInfo(TStrings), sTipUser)); case sTiplist of Администраторы: begin frmMDI.mnuAdmin.Visible:=true; frmMDI.mnuLogist.Visible:=true; frmMDI.mnuSales.Visible:=true; frmMDI.mnuLogin.Visible:=true; frmMDI.mnuExit.Visible:=true; end; Логисты: begin frmMDI.mnuAdmin.Visible:=false; frmMDI.mnuLogist.Visible:=true; frmMDI.mnuSales.Visible:=false; frmMDI.mnuLogin.Visible:=true; frmMDI.mnuExit.Visible:=true; end; Кассиры: begin frmMDI.mnuAdmin.Visible:=false; frmMDI.mnuLogist.Visible:=false; frmMDI.mnuSales.Visible:=true; frmMDI.mnuLogin.Visible:=true; frmMDI.mnuExit.Visible:=true; end; end; //Раз пароль подошел, то получаем из записи таблицы БД остальные //характеристики пользователя iIDUser:=adoLogin.fieldbyname('ID_пользователя').AsInteger; sFIOUser:=adoLogin.fieldbyname('ФИО').AsString; //Присваиваем ФИО сотрудника, вошедшего в систему из набора sDolgnostUser:=adoLogin.fieldbyname('Должность').AsString; //Устанавливаем для главной формы заголовок frmMDI.Caption:='Автовокзал - '+'Пользователь: '+sLogin+' '+'ФИО: '+sFIOUser+' '+'Тип: '+sTipUser+' '+'Должность: '+sDolgnostUser; frmMDI.AlphaBlendValue:=255;//Делаем главную форму видимой Close;//и закрываем окно авторизации end else //Если введенный пароль не совпал с тем, который в записи, то //выводим окно с сообщением. begin Application.CreateForm(TfrmGray,frmGray);//Вызываем окно-темную подложку Application.CreateForm(TfrmMessage,frmMessage); frmMessage.Left:=Round(Left +(Width-frmMessage.Width)/2); frmMessage.Top:=Round(Top +(Height-frmMessage.Height)/2+20); frmMessage.lblMessage.Caption:='Пароль не верный! Обратитесь к администратору системы!'; frmMessage.ShowModal(); frmGray.Close; end; end;
Кнопка Отмена будет содержать довольно простой код:
procedure TfrmLogin.cmdCancelClick(Sender: TObject); begin Application.Terminate //завершаем приложение end;
Надо иметь ввиду, что это довольно простой код и его можно всячески усовершенствовать. Плюс ко всему для его работы у меня используются дополнительные формы, такие как frmMessage, frmGray, которые я создавал заранее. Можно не использовать, например frmGray, которая создает затемнение перед показом модального окна с сообщением frmMessage. Можно не использовать frmMessage, а использовать вместо него встроенные в Delphi функции вывода сообщений.
В этом посте я просто хотел показать один из интересных подходов к созданию форм авторизации в системе программирования Delphi. Если кому то что-то не понятно, вы можете задать вопросы, на которые я постараюсь ответить.
В следующем посте рассмотрим, как создавать простые формы авторизации в приложении SDI-типа.