Java ORM | Контроль доступа
Принцип работы
При подключении к базе данных из системных представлений загружаются привилегии на таблицы, которые связаны с соответствующим record-классом, и список ролей пользователя. Список привилегий и ролей также доступен без использования ORM.Для каждой таблицы возможно добавить настраиваемое поле ACL (Access Control List), при этом при ORM-операциях будет проверяться доступ.
В нестандартных случаях можно переопределить метод hasPrivilege.
Пример использования
Обзорное видео
1. Создаем таблицу test.message, наполняем ее данным и определяем доступ
create table test.message( id serial primary key, acl varchar(32), text varchar(64) ); insert into test.message(acl, text) values (null, 'Without control'); insert into test.message(acl, text) values ('{r_example_access_control=suda}','Full'); insert into test.message(acl, text) values ('{example_access_control=s}','Read only'); insert into test.message(acl, text) values ('{}','No access'); drop role if exists r_example_access_control; create role r_example_access_control; grant usage on schema test to r_example_access_control; grant select,delete on test.message to r_example_access_control; drop user if exists example_access_control; create user example_access_control with password 'example'; grant connect on database exampledb to example_access_control; grant select on pg_authid to example_access_control; grant r_example_access_control to example_access_control; /* select * from test.message; drop table test.message; revoke select on pg_authid from example_access_control; revoke connect on database exampledb from example_access_control; drop user if exists example_access_control; revoke usage on schema test from r_example_access_control; drop role if exists r_example_access_control; */
2. Запускаем Class Generator, подключаемся к базе данных и генерируем классы Message и MessageList

3. Java-пример: подключаемся к базе данных, проверяем привилегии на таблицы и список ролей, считываем записи, при попытке сохранения записи получаем исключение
package org.jarovit.example.orm; import org.jarovit.database.adapter.DatabaseAdapter; import org.jarovit.database.adapter.DatabaseAdapter.DatabaseObjectPrivilege; import org.jarovit.database.adapter.DatabaseAdapter.DatabaseObjectType; import org.jarovit.database.adapter.PostgreSQLDatabaseAdapter; import org.jarovit.example.orm.database.test.orm.record.Message; import org.jarovit.example.orm.database.test.orm.record.MessageList; public class ExampleOrmAccessControl { public static void main(String[] args) { try { // Create ORM-adapter and connect to database DatabaseAdapter databaseAdapter = new PostgreSQLDatabaseAdapter(); databaseAdapter.connect("jdbc:postgresql://127.0.0.1:5432/exampledb", "example_access_control", "example"); // Print user privileges on the table System.out.println("Privileges:"); for(DatabaseObjectPrivilege privilege : DatabaseObjectPrivilege.values()) System.out.println(" "+privilege+" "+databaseAdapter.hasUserPrivilege(DatabaseObjectType.TABLE, "test", "message", privilege)); // Print roles System.out.println("All roles:"); databaseAdapter.getAllRoles().stream().forEach(System.out::println); System.out.println("User roles:"); databaseAdapter.getUserRoles().stream().forEach(System.out::println); // Load(select) only accessible record System.out.println("Loaded records:"); MessageList messageList = MessageList.loadAll(databaseAdapter); for(Message message : MessageList.loadAll(databaseAdapter)) System.out.println(" "+message.getText()+", "+message.getAcl()); // Try to save the record without privileges and get exception System.out.println("Try to save record with ACL 'read only':"); Message message = MessageList.load(databaseAdapter, "text=?", new Object[] {"Read only"}).getFirst(); try { message.save(); } catch(Exception exceptionSave) { System.err.println(" "+exceptionSave.getMessage()); } } catch(Exception exception) { exception.printStackTrace(); } } }