В прошлой статье Авторизация на Delphi мы рассмотрели один из способов организации появления окна авторизации пользователя. Мы рассматривали этот вопрос в отношении приложения многодокументного типа. В этой статье акцент будет сделан на однодокументное приложение SDI типа.
Что такое SDI и MDI типы приложений?
SDI-приложение — это приложение однодокументного типа (Single document interface). Это означает, что все окна приложения не принадлежат какому-то общему окну, а открываются сами по себе и в диспетчере задач Windows каждое открытое окно будет высвечиваться на своей вкладке. Примером такого типа приложений является MS Word, MS Excel и другие программы из пакета MS Office.
Здесь каждый созданный файл (документ Word или книга Excel) будут открываться в отдельном окне и выглядеть при этом как отдельно открытый экземпляр приложения, хотя на самом деле это и не так. В самых ранних версиях эти приложения была MDI типа.
MDI-приложение — это многодокументный тип приложения (multiple document interface). Интерфейс MDI типа подразумевает одно главное окно приложения, в котором будут открываться все остальные окна. Примером такого приложения может служить CorelDraw или Adobe Photoshop, Adobe Reader...
Схема авторизации пользователя
Наверное с этого следовало бы начать в предыдущей статье об авторизации. Но я думаю, что мы посмотрим на один из вариантов схемы в этой. Ничего страшного, давайте приступим.
Итак, авторизация может быть организована следующим образом. Все пользователи должны быть где то учтены. очень удобно для этих целей использовать базу данных. Да и вообще, если приложение разрабатывается для работы с базами данных (для чего чаще всего и используется Delphi), то тогда на самом деле стоит хранить всю информацию о пользователях именно в базе данных.
Так как я люблю работать с MySQL я буду показывать скрины на его примере. Но на других СУБД, таких как MS SQL Server, MS Access и других способ организации точно такой же.
Итак, для хранения информации о пользователях можно использовать одну таблицу. Но мы немного усложним задачу, чтобы сделать ее интересней. Для хранения информации об аккаунтах, мы будем использовать три таблицы:
- Роли. В этой таблице мы будем хранить информацию о ролях пользователей;
- Пользователи. В данной таблице будет храниться информация обо всех пользователях, которым будет открываться доступ к программе;
- Аккаунты. Данная таблица будет содержать в себе открытые аккаунты (личные кабинеты, учетные записи). Для чего нужна эта таблица? Все очень просто. Один и тот же пользователь может иметь более одной учетной записи. Например, он может быть администратором и каким то другим специалистом.
Тогда схема таблиц для авторизации пользователей будет выглядеть так:
Мы видим две родительские таблицы (Роли и Пользователи) и одну дочернюю — Аккаунты. Естественно, что связь между Роли и Аккаунты, а также Пользователи и Аккаунты будет как один-ко-многим. Почему? Потому что один и тот же пользователь, как я говорил выше в нашем примере может иметь несколько ролей. Ровно как и одна и та же роль может быть назначена разным пользователям. Это называется отношение много-ко многим.
Отношение много-ко-многим присутствует между таблицами Роли и Пользователи. Но такое отношение не назначается напрямую, а решается с помощью промежуточной (объединяющей таблицы). В нашем случае это таблица Аккаунты.
Теперь давайте вернемся к непосредственной авторизации на Delphi и рассмотрим вопрос о том, как сделать авторизацию пользователя.
Форма авторизации пользователя
В окне дизайнера форм данная форма может выглядеть так, как показано на рисунке ниже:
Обычно модуль, описывающий форму авторизации пользователя я называю login.pas, форму именую как frmLogin. Задавать корректные имена очень удобно. Не следует оставлять элементы с именами по умолчанию.
Также в этой форме присутствует раскрывающийся список (TCombobox) и текстовое поле (TEdit), две кнопки класса TPanel и один компонент доступа к данным типа (TadoQuery).
В данном примере кнопки представлены компонентом TPanel, а не TButton. Это сделано для того, чтобы мне было легче придать интерфейсу тот вид, которого я хотел добиться. Эти вещи можно сделать и по другому, а именно можно использовать стили и тогда можно использовать обычные кнопки, но назначать им стили отображения. Это другой способ. Но это не тема данной статьи, а небольшое отступление, поэтому больше здесь мы это затрагивать не будем.
Собственно весь дальнейший процесс описан в предыдущей статье Авторизация на Delphi. Здесь я покажу только то, как заполняется список из логинов, потому что в предыдущей статье я не описывал это...
Для заполнения списка логинами я использую компонент набора данных TadoQuery с именем adoLogin.
В свойстве SQL данного компонента я использую запрос:
SELECT
роли.Код_роли,
роли.Роль,
пользователи.Код_пользователя,
пользователи.ФИО,
аккаунты.Код_аккаунта,
аккаунты.Логин,
аккаунты.Пароль
FROM
роли
INNER JOIN аккаунты ON аккаунты.Код_роли = роли.Код_роли
INNER JOIN пользователи ON аккаунты.Код_пользователя = пользователи.Код_пользователя
WHERE аккаунты.Статус = 'Действующий'
В событии onCreate (когда у нас создается форма для авторизации пользователя) мы пишем следующий код:
procedure TfrmLogin.FormCreate(Sender: TObject);
var
KolZap: integer;
TekZap: integer;
i: integer; // Счетчик
begin
//Прячем все пункты меню
frmMDI.mnuAdmin.Visible:=false;
frmMDI.mnuLogin.Visible:=false;
frmMDI.mnuTovar.Visible:=false;
frmMDI.mnuKont.Visible:=false;
frmMDI.mnuDv.Visible:=false;
frmMDI.mnuAnalis.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;
//Ставим первое значение в списке по умолчанию
cboLogin.ItemIndex:=0;
end;
Теперь после запуска приложения и появления окна авторизации раскрывающийся список Имя пользователя будет заполнен логинами из набора данных, полученного на основе запроса на объединение данных из трех таблиц (Роли, Пользователи и Аккаунты).
В кнопке Вход нужно прописать такой код:
procedure TfrmLogin.pnlFirstGroupClick(Sender: TObject);
var
sTiplist: TStrings;
sTiplistUser: String;
sPassword: string;
begin
sLogin:=cboLogin.Text;
sPassword:=trim(txtPassword.Text);
//Теперь проверяем пароль пользователя
adoLogin.First;//Ставим указатель на первую запись таблицы
adoLogin.Locate('Логин', sLogin,[]);// Находим в таблице запись с выбранным логином
if adoLogin.fieldbyname('Пароль').AsString = sPassword then //Если пароль совпадает с введенным, то
begin
//Заменяем пробелы на подчеркивание, потому что в строковом перечислении
//пробелы не работают пробелы
sTipUser:=adoLogin.fieldbyname('Роль').AsString;
sTiplistUser:=StringReplace(adoLogin.fieldbyname('Роль').AsString, ' ', '_',[rfReplaceAll, rfIgnoreCase]);
sTiplist:=TStrings(GetEnumValue(TypeInfo(TStrings), sTiplistUser));
case sTiplist of
Администраторы:
begin
frmMDI.mnuAdmin.Visible:=true;
frmMDI.mnuLogin.Visible:=true;
frmMDI.mnuTovar.Visible:=true;
frmMDI.mnuKont.Visible:=true;
frmMDI.mnuDv.Visible:=true;
frmMDI.mnuAnalis.Visible:=true;
end;
Менеджеры:
begin
frmMDI.mnuAdmin.Visible:=false;
frmMDI.mnuLogin.Visible:=true;
frmMDI.mnuTovar.Visible:=true;
frmMDI.mnuKont.Visible:=true;
frmMDI.mnuDv.Visible:=true;
frmMDI.mnuAnalis.Visible:=true;
end;
Кладовщики:
begin
frmMDI.mnuAdmin.Visible:=false;
frmMDI.mnuLogin.Visible:=true;
frmMDI.mnuTovar.Visible:=false;
frmMDI.mnuKont.Visible:=false;
frmMDI.mnuDv.Visible:=true;
frmMDI.mnuAnalis.Visible:=false;
end;
end;
//Раз пароль подошел, то получаем из записи остальные
//характеристики пользователя
iIDUser:=adoLogin.fieldbyname('Код_аккаунта').AsInteger;
sFIOUser:=adoLogin.fieldbyname('ФИО').AsString; //Присваиваем ФИО пользователя, вошедшего в систему из набора
//Устанавливаем для главной формы заголовок
frmMDI.Caption:='Мониторинг складского учета торговой сети - '+'Пользователь: '+sLogin+' '+'ФИО: '+sFIOUser+' '+'Роль: '+sTipUser;
frmMDI.AlphaBlendValue:=255;//Делаем главную форму видимой
Close;//и закрываем окно авторизации
end else //Если введенный пароль не совпал с тем, который в записи, то
begin
MessageCreate(Left,Top,Height,Width,'Пароль не верный! Обратитесь к администратору системы!');
end;
end;
Здесь MessageCreate — это моя пользовательская процедура создания окна сообщения. Вы можете вместо нее использовать, например стандартную функцию MessageBox или свою собственную форму, разработанную в Delphi.
Это был все также пример для MDI-приложения. Его я показал для того, что бы рассмотреть идею общей организации схемы авторизации пользователя на Delphi.
Хочу также отметить, что в данном примере всех пользователей создает администратор. Он же и назначает пользовательский пароль. Здесь пользователь не создает учетную запись самостоятельно. Это достаточно распространенный метод в бизнес-приложениях. После создания учетной записи, администратор отдает новому пользователю парольную карточку.
Форма авторизации пользователя в SDI-приложении на Delphi
Все, что будет написано ниже справедливо как для библиотеки VCL, так и для кроссплатформенной библиотеки FMX.
В автозапуске оставляем только основную форму. Допустим называется она frmSDI. Форму frmLogin убираем из автозапуска. В форме frmSDI объявляем глобальную переменную: zapusk: boolean;
В событии OnCreate формы frmSDI этой переменной присваиваем True.
procedure TfrmSDI.FormCreate(Sender: TObject);
begin
zapusk:=true;
end;
В событии OnShow формы frmSDI пишем:
procedure TfrmSDI.FormShow(Sender: TObject);
begin
if Zapusk=true then
begin
Application.CreateForm(TfrmLogin, frmLogin);
frmLogin.Show;
frmSDI.Hide;
end;
end;
В событии OnCreate формы frmLogin пишем:
procedure TfrmLogin.FormCreate(Sender: TObject);
begin
Zapusk:=false;
end;
В событии OnDestroy формы frmLogin пишем:
procedure TfrmLogin.FormDestroy(Sender: TObject);
begin
zapusk:=true;
end;
Сама же форма авторизации пользователя (frmLogin) , будет точно такой же, как и в случае с приложением MDI-типа. Итак, мы рассмотрели некоторые вопросы по созданию формы авторизации пользователей на Delphi. Надеюсь, что материал будет полезным для вас.