Универсальный дизайн разрешения данных

Java Spring Безопасность Shiro
выявленная проблема

В последнее время многие студенты сообщают, что проекту необходимо иметь дело с разрешениями на доступ к данным, но они не знают, как правильно с этим справиться. В этой заметке представлена ​​более общая и легко расширяемая схема проектирования разрешений на доступ к данным для решения этой проблемы.

статус кво

В настоящее время популярная структура разрешений уже поддерживает разрешение данных, но ее необходимо настроить в интерфейсе и методе, а масштабируемость не очень хорошая, так как же мы можем максимизировать масштабируемость?

Придумать несложно: поместить контроль разрешений данных в базу данных, и сначала определить, есть ли доступ у интерфейса при перехвате разрешения.После того, как у интерфейса есть доступ, то определить, имеют ли указанные параметры право на использование настроенные условия.значение. (Чтобы сделать это более продвинутым, вы можете проверить возвращаемый результат. Если доступ к объекту, содержащему определенное значение, запрещен, он также рассматривается как несанкционированный доступ. Эта ситуация пока не рассматривается в этой заметке). Как это сделать?

Дизайн базы данных

Давайте начнем с дизайна таблицы базы данных, сначала определим структуру таблицы управления правами доступа к данным:

     CREATE TABLE `sys_acl_data` (
        `id` int(11) NOT NULL,
        `acl_id` int(11) NOT NULL COMMENT '对应权限表主键',
        `status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '状态,1:可用,0:不可用',
        `param` varchar(20) NOT NULL DEFAULT '' COMMENT '参数',
        `operation` int(11) NOT NULL DEFAULT 0 COMMENT '操作类型,0;等于,1:大于,2:小于,3:大于等于,4:小于等于,5:包含,6:介于之间,。。。',
        `value1` varchar(100) NOT NULL DEFAULT '0',
        `value2` varchar(100) NOT NULL DEFAULT '0',
        `next_param_op` int(11) NOT NULL DEFAULT 0 COMMENT '后续有参数时连接的关系,0:没有其他参数控制,1:与&&,2:或||',
        `seq` tinyint(4) NOT NULL DEFAULT '0' COMMENT '顺序',
        PRIMARY KEY (`id`),
        INDEX `idx_acl_id` USING BTREE (`acl_id`)
    ) ENGINE=`InnoDB` COMMENT '数据权限表';

Подробно опишите значение каждого поля:

идентификатор первичного ключа;

acl_id сопоставляет первичный ключ таблицы точек разрешений, который представляет, для какой точки разрешений предназначена каждая строка записей;

статус показывает, действительна ли текущая конфигурация, что удобно для временной активации и деактивации;

param представляет имя параметра, который необходимо проверить, что позволяет запросу иметь несколько параметров для участия в проверке данных; если параметры сложные, например, содержащие объекты, определенные параметры могут быть в форме многоуровневых abc , рекомендуется не слишком усложнять

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

значение1 и значение2 используются для формирования реляционного выражения с параметром и операцией, например: 1

Поле next_param_op используется по мере необходимости.Если точка разрешения поддерживает несколько правил данных, соедините операции между двумя правилами, || или &&

Поле seq используется для порядка, когда точка разрешения содержит несколько правил разрешения данных.

图片描述

Предположим, что есть такой фрагмент данных, тогда его значение: точка доступа, id которой равен 1 (acl_id), настроена с допустимым (status=1) правилом данных, правило такое: значение входящего параметра id (param ) должно быть больше (операция) 10 (значение1)

Логика проверки разрешений на доступ к данным

После структуры таблицы следующим шагом будет добавление интерфейсов для обновления и получения данных, а затем страница для отображения и добавления к ней операций, здесь я не буду занимать больше места и сосредоточусь на обработке логики . . .

курс разрешенияЯ не буду повторять базовое управление и перехват разрешений точек разрешений в нативной реализации набора управления разрешениями в этом разделе.Достаточно посмотреть видео и код.Здесь я сосредоточусь на том, как выполнять данные разрешения на существующих разрешениях .расширение. Во-первых, дайте основной код перехвата URL-адресов и проверки разрешений (вы должны быть в состоянии понять это, взглянув только на этот код, не вникая в детали курса):

   自定义filter拦截url判断权限核心代码:
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String servletPath = request.getServletPath();
        Map requestMap = request.getParameterMap();

        if (exclusionUrlSet.contains(servletPath)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        SysUser sysUser = RequestHolder.getCurrentUser();
        if (sysUser == null) {
            log.warn("someone visit {}, but no login, parameter:{}", servletPath, JsonMapper.obj2String(requestMap));
            noAuth(request, response);
            return;
        }
        SysCoreService sysCoreService = ApplicationContextHelper.popBean(SysCoreService.class);
        if (!sysCoreService.hasUrlAcl(servletPath)) {
            log.warn("{} visit {}, but no login, parameter:{}", JsonMapper.obj2String(sysUser), servletPath, JsonMapper.obj2String(requestMap));
            noAuth(request, response);
            return;
        }

        filterChain.doFilter(servletRequest, servletResponse);
        return;
    }

    实际判断一个url是否可访问的核心代码:
    public boolean hasUrlAcl(String url) {
        if (isSuperAdmin()) { // 超级管理员直接允许访问
            return true;
        }
        List<SysAcl> aclList = sysAclMapper.getByUrl(url); // 取出符合条件的权限点
        if (CollectionUtils.isEmpty(aclList)) {  
            return true;
        }

        List<SysAcl> userAclList = getCurrentUserAclListFromCache();
        Set<Integer> userAclIdSet = userAclList.stream().map(acl -> acl.getId()).collect(Collectors.toSet());

        boolean hasValidAcl = false;
        // 规则:只要有一个权限点有权限,那么我们就认为有访问权限
        for (SysAcl acl : aclList) {    // -----------------------------------------------------  ①
            // 判断一个用户是否具有某个权限点的访问权限
            if (acl == null || acl.getStatus() != 1) { // 权限点无效
                continue;
            }
            hasValidAcl = true;
            if (userAclIdSet.contains(acl.getId())) {
                return true;           // ------------------------------------------------------  ②
            }
        }
        if (!hasValidAcl) {
            return true;              // -------------------------------------------------------  ③
        }
        return false;
    }

Из ① в коде вы можете получить фактическую точку разрешения для оценки. При оценке того, что указанная точка доступа имеет разрешение на доступ, необходимо добавить проверку разрешения данных в ② и ③ кода.

Теперь, когда вы хотите проверить параметры, вам нужно передать параметры в метод hasUrlAcl. В методе doFilter Map requestMap = request.getParameterMap(); requestMap — это список параметров URL-адреса Этот метод не полностью применим к некоторым специальным сообщениям, таким как передача параметров в формате json в теле. Способ передачи параметров методу в реальном проекте может быть обработан в соответствии с фактическим определением интерфейса проекта.

Когда hasUrlAcl получает параметр и решает, что указанная точка доступа имеет доступ, перейдите к таблице sys_acl_data, чтобы запросить список допустимых правил в соответствии с acl_id, и оцените каждый элемент один за другим.Обратите внимание на обработку многих деталей здесь. 1. Интерпретация одного правила, 2. Логические И и ИЛИ между несколькими правилами, 3. Интерпретация параметров с иерархическими уровнями (abc), на практике сложность обработки можно определить по определению и спецификации интерфейса в проект. После этой реализации, когда URL-адрес имеет доступ, нет правила данных или проверка правила данных пройдена, URL-адрес действительно авторизован для доступа.

В это время кто-то обязательно спросит, как мне перехватить права доступа к данным, когда мой интерфейс определен как этот /a/{id}.json? На самом деле, интерфейс этого метода может быть поддержан небольшими корректировками в ходе курса, которые заключаются в следующем:

    SysAclMapper.xml:
    <select id="getByUrl" parameterType="string" resultMap="BaseResultMap">
        SELECT <include refid="Base_Column_List" />
        FROM sys_acl
        WHERE url = #{url} <!-- url is not null and url != '' and  #{url} REGEXP url-->
     </select>

Содержимое комментария должно включать регулярное сопоставление, которое должно соответствовать URL-адресу через регулярность. Здесь используйте URL-адрес не нулевой и URL-адрес != '' и #{url} URL-адрес REGEXP вместо url = #{url} , и затем настройте каждую точку разрешения.Достаточно использовать обычный, чтобы настроить URL-адрес каждой точки разрешения.Например, когда URL-адрес настроен для проверки разрешений, он может быть настроен как /a/[5|6].json. Конечно, у этого метода есть определенные требования к регулярному выражению администратора полномочий. В настоящее время точки доступа, которые не могут быть проверены при получении квалифицированных URL-адресов, не могут быть получены. Если вы не можете получить его, вы не можете напрямую рассматривать его как сделку. Вы можете рассмотреть возможность настройки разрешения с подстановочным знаком (/a/*.json), когда столкнетесь с этим. Каждый раз, когда вы сопоставляете такой URL-адрес с подстановочным знаком, вы должны убедитесь, что он соответствует содержащему регулярному. Проверка считается только разрешением. Детали этого могут быть обработаны по-разному самостоятельно, здесь только общая идея.

конец

Давайте сначала поговорим о разрешениях данных.Лично я думаю, что вышеописанный метод будет относительно лучше с точки зрения масштабируемости, и он не очень сложен в реализации.Если у вас есть какие-либо вопросы, пожалуйста, укажите.

Другие примечания о разрешении

Реформирование процесса управления полномочиями на фоне операций электронной коммерции

Пользовательский тег JSP автоматически завершает процесс перехвата разрешений для кнопки страницы.