Ответ 1
Просто хочу описать мое решение этой проблемы, которое может быть полезно кому-то. Я считаю, что это может быть не оптимальным, поэтому все еще открыты для любых предложений по более чистой реализации.
Предполагая, что мне необходимо выполнить следующие действия:
- activity: edit
- Активность: вид
И мне также нужно убедиться, что разрешения не являются системными, но зависит от моей роли в определенном отделе. То, что я сделал, явно добавило "зависимое от отдела" разрешение для пользователя в моем Царстве. Пример (см. Иерархию в сообщении):
- DEP_A: активность: вид
- DEP_C: активность: вид
- DEP_C: активность: изменить
Каждый раз, когда я хочу проверить, разрешено ли действие против какой-либо активности, я создаю список разрешений для проверки. Пример:
Активность A принадлежит отделу D, я хочу "просмотреть" его. Разрешения для проверки будут следующими:
- DEP_D: активность: вид
- DEP_C: активность: вид
- DEP_B: активность: вид
Если я являюсь администратором отдела C, я бы получил разрешение "DEP_C: activity: view" и, следовательно, проверка будет передана. Это позволяет реализовать наследование прав в иерархии структуры компании.
Вот код snipplet из моего класса сервиса, ответственного за проверки разрешений:
@Override
public void checkIfOperationPermitted( SecurityOperation operation,
Object object )
{
final Subject currentUser = SecurityUtils.getSubject();
if(currentUser.isPermitted(
SecurityOperation.SYSTEM_ADMIN.getPermissionString()) ||
currentUser.hasRole( "admin" ))
{
// no need to check anything else,
// admin is system wide role.
return;
}
if(object instanceof Activity)
{
// Activity permissions fully depends on organization and
// product hierarchies. PermissionResolver is just a class
// which generates list of permission strings based on
// department activity is belonging to.
Activity a = (Activity) object;
List<String> permissionsToCheck =
permissionResolver.resolveHierarchicalPermissions(operation, a);
boolean permitted = false;
for(String permission: permissionsToCheck)
{
if(currentUser.isPermitted( permission ))
{
permitted = true;
break;
}
}
if(!permitted)
{
throw new UnauthorizedException( "Access denied" );
}
}
else
{
// Check for system wide permissions
currentUser.checkPermission( operation.getPermissionString() );
}
}
Другой способ, о котором я думал, - добавить все такие разрешения для пользователя в моем Realm, но отклонил это, поскольку иерархия компаний может содержать N уровней, что значительно увеличивает дублирование в списке разрешений для конкретного пользователя (использование памяти).