Авторизация на 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-типа.