Как построить хорошую архитектуру безопасности в веб-приложении?

Я хотел бы сделать динамическую безопасность в приложении (весенняя загрузка, весенний mvc, весенняя безопасность, тимелеаф).

Я хочу добавить на страницу своего веб-приложения, где пользователь / администратор может добавить несколько новых разрешений (только имена). На другой странице он сможет добавить, например, новая позиция в меню (или новое поле, или новая вкладка). И когда он добавит этот новый элемент, у него должна быть возможность выбрать, какие разрешения должны иметь пользователи, чтобы видеть эту новую позицию меню (для поля будет одно разрешение для просмотра и одно для редактирования).

У вас есть какие-нибудь решения, как это сделать? Я думал об ALC во время весенней безопасности, но сейчас не думаю, что это хороший выбор.

Может быть, есть способ использовать @PreAuthorize("hasRole()")? Или добавьте что-то вроде таблицы «компонентов», когда я буду помещать все элементы, которые добавляют пользователи. И в этой таблице будет столбец типа «разрешение на редактирование» и «разрешение на просмотр», где я помещаю идентификаторы разрешений и проверяю эту таблицу во всех методах, где я получаю пункты меню, поля ..

Может быть, хорошим решением для этого будет собственная реализация PermissionEvaluator?

0
0
79
1

Ответы 1

Я думаю, вам нужно создать перечисление ролей с таблицей разрешение в базе данных.

  1. Перечисление ролей

    public enum Roles {
       Admin,
       Pm,
       TeamLead,
       User,
       ...
    }
    
  2. Таблица разрешений

| ID | ROLE | WORKSPACE | READ | WRITE | DELETE |
| 1 | Admin | Dashbord | TRUE | TRUE | TRUE |
| 2 | Admin | Employee | TRUE | TRUE | TRUE |
| 3 | Admin | Project | TRUE | TRUE | TRUE |
| 4 | Admin | Task | TRUE | TRUE | TRUE |
| 5 | Admin | Team | TRUE | TRUE | TRUE |
| 6 | Pm | Dashbord | TRUE | FALSE | FALSE |
| 7 | Pm | Employee | TRUE | FALSE | FALSE |
| 8 | Pm | Project | TRUE | TRUE | TRUE |
| 9 | Pm | Task | TRUE | TRUE | TRUE |
| 10 | Pm | Team | TRUE | FALSE | FALSE |
| 11 | TeamLead | Dashbord | TRUE | FALSE | FALSE |
| 12 | TeamLead | Employee | TRUE | TRUE | TRUE |
| 13 | TeamLead | Project | TRUE | FALSE | FALSE |
| 14 | TeamLead | Task | TRUE | FALSE | FALSE |
| 15 | TeamLead | Team | TRUE | TRUE | TRUE |
| 16 | User | Dashbord | FALSE | FALSE | FALSE |
| 17 | User | Employee | TRUE | FALSE | FALSE |
| 18 | User | Project | TRUE | FALSE | FALSE |
| 19 | User | Task | TRUE | TRUE | FALSE |
| 20 | User | Team | TRUE | FALSE | FALSE |

  1. Таблица пользователей в базе данных должна добавить столбец userRole

@Basic
@Enumerated(EnumType.STRING)
private Roles userRole;

  1. Создайте пользовательский интерфейс аннотации, проверьте текущего пользователя по разрешению роли

    @Retention(RetentionPolicy.RUNTIME) public @interface PermissionCheck {

    String[] workspace() default {};
    
    boolean read() default false;
    
    boolean write() default false;
    
    boolean delete() default false; }
    

@Aspect @Component public class PermissionAspect {

@Autowired
private PermissionRepository permissionRepository;

@Around("execution(@com.security.annotation.springbootsecuritypermission

.aspect.PermissionCheck * *(..)) && @annotation(permissionCheck)") public Object doSomething(ProceedingJoinPoint pjp, PermissionCheck >permissionCheck) throws Throwable { if(permissionCheck.workspace().length>0 && SecurityUtil.getUser()!=null){ List permissionList = permissionRepository.findByRolesAndWorkspaceIn( SecurityUtil.getUser().getRoles(),permissionCheck.workspace());

       Function<PermissionEntity,Boolean> permissionFunction = new Function<PermissionEntity, Boolean>() {
           @Override
           public Boolean apply(PermissionEntity permissionEntity) {
               if(permissionCheck.read() && permissionEntity.getRead()) {
                   return true;
               }
               if(permissionCheck.write() && permissionEntity.getWrite()) {
                   return true;
               }
               if(permissionCheck.delete() && permissionEntity.getDelete()) {
                   return true;
               }
               return false;
           }
       };

       final boolean[] hasPermission = {false};
       permissionList.forEach(permissionEntity -> {
           hasPermission[0] = permissionFunction.apply(permissionEntity);
           if(hasPermission[0]){
               return;
           }
       });

        if(!hasPermission[0]){
            throw new AccessDeniedException("Do not has permission");
        }

    }
    return pjp.proceed();
} }
  1. Вы можете использовать пользовательские аннотации для методов

    @GetMapping("dashboard") @PermissionCheck(workspace = {Workspace.DASHBOARD},read = true) public String dashboard() {
    return "dashboard"; }

Если вы меня не очень хорошо поняли, вы можете открыть эту ссылку https://github.com/Dilsh0d/spring-boot-security-permission.

Другие вопросы по теме