Здравствуйте! В интернете нашел бухгалтерскую программу AZMicro2, написанную Архангельским (автор книг про Delphi), БД Firebird 2.0 и собираюсь разобраться в созданной автором системе безопасности.
https://drive.google.com/open?id=1IkPyUEmN0hD_QD33rjhFuYWNITZ9MCnY
Отривок из файла:
Система безопасности
Несмотря на то, что СУБД поддерживает таблицу пользователей, но в данном случае она не поможет......
Итак, строим таблицу Users:
Users
Таблица Users описывает как пользователей, так и их права для доступа к другим таблицам. Таким образом права устанавливает Администратор системы и пользователь может не задумываться о том с какими правами ему нужно входить. Если он вошел в систему, то она покажет ему только то, что разрешено.
Основные поля этой таблицы — USERID и USERNAME. Первое используется как первичный ключ и используется во всех связях, а второе уникальное имя пользователя, которое определено в БД fbsecurity.fb, и вводится пользователем в качестве Login при входе в систему.
Поля USRSYSNAME, USRDOMAIN, USRNames, USRNPost — это описательные поля, которые являются справочником для администратора.
Для определения прав доступа используются поля USRGroup, USRLevel, USRRole, которые определяются из таблицы "Система безопасности".
И, наконец, блок контроля, который имеется во всех таблицах. Для каждой строки определяются КТО и КОГДА создал запись, а также КТО и КОГДА изменил запись. Если возникнет задача репликации, т.е. перенос части этой БД в другую, то всегда можно определить новые и измененные записи.
Но кроме определения таблицы нужно заполнить ее хотя бы одной записью и наложить ограничения на структуру и другие действия.
Первая запись определяет USERID, который вводится во все таблицы по умолчанию:
Insert into Users(UserID,UserName,USRNames,USRRole)
values(0,'SYSDBA','Создатель БД','A1');
Commit;
Далее наложить ограничения, что в поля USRCreate и USRModify можно вводить только значения из самой таблицы Users.
Для заполнения первичного ключа нужно использовать генератор и соответствующий триггер.
После всего этого нужно наложить правила, по которым можно заполнять и изменять информацию в этой таблице.
Во-первых, нужно определить какие действия являются ошибочными. В языке SQL они называются Exception (исключениями). Они не только прерывают выполнение операции, но и сообщают пользователю о его ошибке.
— нужно ограничить создание определенных ролей. Ну, не должно быть двух Директоров или Главных бухгалтеров.
— нужно запретить удаления из этой таблицы или неправомерное изменение уровня доступа.
Во-вторых, нужно создать триггеры, которые определяют эти правила:
Обяснение триггера:
Сначала определяем КТО пытается создать новую запись и какими правами он обладает и отмечаем это в полях new.UsrCreate и new.UsrModify.
Select USERID, USRRole,USRLevel from USERS where USERNAME=USER into :USR,:Rls,:Lev;
new.USRRole = new.USRGroup||Cast(new.USRLevel as Char(1));
new.UsrCreate = USR;
new.USRModify = USR;
Потом отсекаем тех, кто не может создавать записи в этой таблице — это пользователи с уровнем доступа более 2. Т.е. новые записи могут создавать только начальники подразделений.
IF (Lev>2) then Exception NoRoleInsert;
Далее определяем, что начальник подразделения может создавать записи только своего подразделения (FinDirector может создавать любые записи).
If ((Rls='F2') and (new.USRGroup<>'F')) then Exception NoRoleInsert;
И, наконец, определяем наличие ключевых должностей в таблице и если они уже есть, то вызываем исключение.
У меня возник 2 вопроса и прошу вашей помощи:
1) Если автор не использует встроенную систему безопасности сервера (в файле security3.fdb не создаёт пользователей), а создаёт свою систему безопасности тогда откуда получает в запросе внутри триггера значение переменной USER (текущий пользователь)? Тогда разве в файле безопасности не будет только суперпользователь SYSDBA?
А если использует встроенную систему безопасности сервера и создаёт там пользователей тогда как они окажутся и в таблице users?
2) Как видите в create table users в комментариях автор пишет:
т.е. пока создаётся пользователь в security3.fdb и сразу в таблице users?
например так, с помощью компонента FDScript?
Или что-то неправильно понял?
https://drive.google.com/open?id=1IkPyUEmN0hD_QD33rjhFuYWNITZ9MCnY
Отривок из файла:
Система безопасности
Несмотря на то, что СУБД поддерживает таблицу пользователей, но в данном случае она не поможет......
Итак, строим таблицу Users:
Users
Таблица Users описывает как пользователей, так и их права для доступа к другим таблицам. Таким образом права устанавливает Администратор системы и пользователь может не задумываться о том с какими правами ему нужно входить. Если он вошел в систему, то она покажет ему только то, что разрешено.
Create table USERS (USERID AZMID NOT NULL PRIMARY KEY, USERNAME AZNAMES NOT NULL UNIQUE, -- Login из fbsecurity.fb (ISC4.gdb) USRSYSNAME AZNAMES, -- из fbsecurity.fb (ISC4.gdb) USRDOMAIN AZNAMES, -- из fbsecurity.fb (ISC4.gdb) USRNames AZLNAME, -- Фамилия, Имя, Отчество USRNPost AZLNAME, -- Должность /* ************************************************************************************* */ USRGroup CHAR(1) character set win1251, -- Текущая группа доступа USRLevel AZInt32, -- Текущий уровень доступа USRRole CHAR(2) character set Win1251, -- Допустимая группа и уровень доступа /*Блок контроля - начало*/ DtCreate AZTStamp, UsrCreate AZMID0, /*references USERS on UPDATE cascade*/ DtModify AZTStamp, UsrModify AZMID0); /*references USERS on UPDATE cascade*/ /*Блок контроля - конец*/ Commit;
Основные поля этой таблицы — USERID и USERNAME. Первое используется как первичный ключ и используется во всех связях, а второе уникальное имя пользователя, которое определено в БД fbsecurity.fb, и вводится пользователем в качестве Login при входе в систему.
Поля USRSYSNAME, USRDOMAIN, USRNames, USRNPost — это описательные поля, которые являются справочником для администратора.
Для определения прав доступа используются поля USRGroup, USRLevel, USRRole, которые определяются из таблицы "Система безопасности".
И, наконец, блок контроля, который имеется во всех таблицах. Для каждой строки определяются КТО и КОГДА создал запись, а также КТО и КОГДА изменил запись. Если возникнет задача репликации, т.е. перенос части этой БД в другую, то всегда можно определить новые и измененные записи.
Но кроме определения таблицы нужно заполнить ее хотя бы одной записью и наложить ограничения на структуру и другие действия.
Первая запись определяет USERID, который вводится во все таблицы по умолчанию:
Insert into Users(UserID,UserName,USRNames,USRRole)
values(0,'SYSDBA','Создатель БД','A1');
Commit;
Далее наложить ограничения, что в поля USRCreate и USRModify можно вводить только значения из самой таблицы Users.
ALTER TABLE USERS add foreign key (USRCreate) references USERS on update cascade; ALTER TABLE USERS add foreign key (USRModify) references USERS on update cascade; Commit;
Для заполнения первичного ключа нужно использовать генератор и соответствующий триггер.
CREATE GENERATOR USERS_GEN; SET GENERATOR USERS_GEN TO 0; Commit; SET TERM ^ ; CREATE TRIGGER USERS_INSGEN FOR USERS ACTIVE BEFORE INSERT POSITION 0 AS BEGIN NEW.USERID = GEN_ID(USERS_GEN,1); END ^ SET TERM ; ^ Commit;
После всего этого нужно наложить правила, по которым можно заполнять и изменять информацию в этой таблице.
Во-первых, нужно определить какие действия являются ошибочными. В языке SQL они называются Exception (исключениями). Они не только прерывают выполнение операции, но и сообщают пользователю о его ошибке.
— нужно ограничить создание определенных ролей. Ну, не должно быть двух Директоров или Главных бухгалтеров.
— нужно запретить удаления из этой таблицы или неправомерное изменение уровня доступа.
Во-вторых, нужно создать триггеры, которые определяют эти правила:
SET TERM ^ ; CREATE TRIGGER USERS_INSERT FOR USERS ACTIVE BEFORE INSERT POSITION 1 AS DECLARE VARIABLE USR SmallInt; DECLARE VARIABLE Cnt SmallInt; DECLARE VARIABLE Lev SmallInt; DECLARE VARIABLE Rls Char(2) character set win1251; BEGIN Select USERID, USRRole,USRLevel from USERS where USERNAME=USER into :USR,:Rls,:Lev; new.USRRole = new.USRGroup||Cast(new.USRLevel as Char(1)); new.UsrCreate = USR; new.USRModify = USR; IF (Lev>2) then Exception NoRoleInsert; If ((Rls='F2') and (new.USRGroup<>'F')) then Exception NoRoleInsert; If ((Rls='T2') and (new.USRGroup<>'T')) then Exception NoRoleInsert; If ((Rls='S2') and (new.USRGroup<>'S')) then Exception NoRoleInsert; If ((Rls='P2') and (new.USRGroup<>'P')) then Exception NoRoleInsert; IF (new.USRRole='A0') then begin Select count(*) from USERS where USRRole='A0' into :Cnt; If (Cnt>0) then Exception A0Exists; end IF (new.USRRole='D0') then begin Select count(*) from USERS where USRRole='D0' into :Cnt; If (Cnt>0) then Exception D0Exists; end IF (new.USRRole='A1') then begin Select count(*) from USERS where USRRole='A1' into :Cnt; If (Cnt>0) then Exception RoleDisable; end IF (new.USRRole='F1') then begin Select count(*) from USERS where USRRole='F1' into :Cnt; If (Cnt>0) then Exception F1Exists; end IF (new.USRRole='F2') then begin Select count(*) from USERS where USRRole='F2' into :Cnt; If (Cnt>0) then Exception F2Exists; end и т.д. .................. END ^ SET TERM ; ^ Commit;
Обяснение триггера:
Сначала определяем КТО пытается создать новую запись и какими правами он обладает и отмечаем это в полях new.UsrCreate и new.UsrModify.
Select USERID, USRRole,USRLevel from USERS where USERNAME=USER into :USR,:Rls,:Lev;
new.USRRole = new.USRGroup||Cast(new.USRLevel as Char(1));
new.UsrCreate = USR;
new.USRModify = USR;
Потом отсекаем тех, кто не может создавать записи в этой таблице — это пользователи с уровнем доступа более 2. Т.е. новые записи могут создавать только начальники подразделений.
IF (Lev>2) then Exception NoRoleInsert;
Далее определяем, что начальник подразделения может создавать записи только своего подразделения (FinDirector может создавать любые записи).
If ((Rls='F2') and (new.USRGroup<>'F')) then Exception NoRoleInsert;
И, наконец, определяем наличие ключевых должностей в таблице и если они уже есть, то вызываем исключение.
У меня возник 2 вопроса и прошу вашей помощи:
1) Если автор не использует встроенную систему безопасности сервера (в файле security3.fdb не создаёт пользователей), а создаёт свою систему безопасности тогда откуда получает в запросе внутри триггера значение переменной USER (текущий пользователь)? Тогда разве в файле безопасности не будет только суперпользователь SYSDBA?
А если использует встроенную систему безопасности сервера и создаёт там пользователей тогда как они окажутся и в таблице users?
2) Как видите в create table users в комментариях автор пишет:
USERNAME AZNAMES NOT NULL UNIQUE, -- Login из fbsecurity.fb USRSYSNAME AZNAMES, -- из fbsecurity.fb USRDOMAIN AZNAMES, -- из fbsecurity.fb
т.е. пока создаётся пользователь в security3.fdb и сразу в таблице users?
например так, с помощью компонента FDScript?
Begin //вставка в security3.fdb if FUsersInsertEditMode=mInsert then begin if length(editNewPassw.text)=0 then editNewPassw.SetFocus else begin with Fmain.FDScript1 do begin SQLScripts.Clear; SQLScripts.Add; with SQLScripts[0].SQL do begin Add('create user '+editUserName.Text); end; ValidateAll; ExecuteAll; end; end; //вставка в users Fmain.Qusers.Open; if FUsersInsertEditMode=mInsert then begin if (EditNewPassw.Text='') then begin Application.MessageBox('Password is empty!','',MB_ICONERROR); exit; end else begin Fmain.Qusers.insert; Fmain.QusersUsername.AsString:=Editusername.Text; Fmain.Qusersuserpassw.AsString:=MD5DigestToStr(MD5String(Ansiuppercase(EditRepeatNewPassw.Text))); Fmain.Qusers.ApplyUpdates; close; end; End;
Или что-то неправильно понял?