Широ-авторизация (RBAC)

задняя часть Shiro Realm

0. Предисловие

существует[Сертификат Широ]В нем объясняется, как использовать Shiro для доступа к URL-адресам после входа в систему. Для большинства систем вход в систему является лишь первым барьером на пути к безопасности. К некоторым страницам в системе необходимо получить доступ после входа в систему, а для доступа к некоторым требуются определенные разрешения. Например, удаление, замораживание, просмотр доходов по счету и другие конфиденциальные операции.

В этой статье вы узнаете, как реализовать контроль разрешений на основе Широ, который в Широ называется авторизацией.

1. Что такое разрешения

В системе три пользователя A, B и C. Пользователь A является администратором, а пользователи B и C являются обычными пользователями.Все операции удаления в системе должны быть выполнены путем входа в систему с учетной записью администратора.Обычные пользователи не могут удалять данные или даже удалить данные. Кнопки не видны. Мы говорим, что пользователи A, B и C имеют разные разрешения в системе. A имеет разрешение на удаление данных, B и C не имеют разрешения на удаление данных. Представьте себе если нет дизайна разрешений, все пользователи могут Удалить данные, предполагая, что B - новичок, который случайно удалит данные по ошибке... Последствия будут невообразимыми.

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

2. Схема оформления разрешений

Если вы делаете сайт знакомств, есть несколько функций для проверки основной информации противоположного пола, проверки WeChat, проверки номера телефона и проверки домашнего адреса.Обычные пользователи могут проверить только основную информацию, но не могут проверить контактную информацию. и т. д. Вы можете проверить WeChat с пополнением счета на 100 юаней, пополнить счет на 200 юаней, чтобы просмотреть номер телефона, и пополнить счет на 500 юаней, чтобы просмотреть домашний адрес.

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

Пользователь Основная информация Посмотреть WeChat Посмотреть телефон Посмотреть адрес
Чжан Сан
Ли Си
Ван Ву

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

Вы умны и придумываете способ установить уровень членства, пополнить 100 юаней для обычных членов, пополнить 200 юаней для VIP и пополнить 500 юаней для среднего VIP P. Установите уровень членства для каждого члена.В это время ваши данные структура таблицы следующая:

  • Уровень членства — разрешения
уровень членства Основная информация Посмотреть WeChat Посмотреть телефон Посмотреть адрес Посмотреть видео
Пополнение счета на 100 юаней: младший член
Пополнение счета на 200 юаней: VIP
Пополнение счета на 500 юаней: P в VIP
  • Членство - Уровень членства
имя пользователя уровень членства
Чжан Сан рядовой член
Ли Си VIP
Ван Ву П в VIP
Чжао Лю П в VIP

В это время, когда пользователь просматривает WeChat, он находит уровень членства в соответствии с пользователем, а затем находит соответствующие разрешения.Хотя есть еще одна операция, но:

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

Короче говоря, полномочия предназначены только для уровня членства и не имеют прямого отношения к членству.Уровень членства здесь эквивалентен системеРоль, схема разрешений на основе ролей принята многими системами и имеет имя собственное:RBAC-Управление доступом на основе ролей.

С точки зрения непрофессионала, это основано на роли пользователя, чтобы определить, есть ли у него разрешение на доступ к ресурсу или URL-адресу.Модель RBAC является классической.5Лист:

  • Пользователь: запись информации о пользователе системы, используемой при входе в систему. Пример: Чжан Сан, Ли Си...
  • Роль: Роли, которые существуют в системе записи Пример: Обычный член, VIP...
  • ресурс: Запишите, что можно сделать в системе.Соответствующий URL-адрес в WEB, например: просмотреть информационный URL-адрес, просмотреть URL-адрес WeChat, просмотреть телефон....
  • Отношение роли пользователя: Запишите роль, которой принадлежит пользователь, например: Чжан Сан — обычный участник, Ли Си — VIP...
  • отношение ресурсов роли: записывает, что может делать персонаж, например: VIP может просматривать информацию, просматривать WeChat...

В системе есть предварительно разработанные роли, ресурсы и отношения роли-ресурса.При создании нового пользователя вам нужно только добавить отношение роли пользователя для управления разрешениями пользователя.Например: Sun Qi зарегистрировал пользователя и перезарядил 200 юаней, мы можем напрямую установить Sun Qi для VIP, через роль VIP Sun Qi, вы можете найти соответствующий действенный URL-адрес из отношения ресурсов роли.

3. Внедрите RBAC в Широ

3.0 Встроенный фильтр

Операции в этой статье основаны на[Сертификат Широ]Рекомендуется сначала прочитать часть аутентификации Широ.Аутентификация Широ выполняется через встроенный фильтр аутентификации (authc), а также предоставляются некоторые фильтры, связанные с авторизацией:

3.0.1 фильтр порта: port

Когда доступ к порту не является определенным портом, перенаправление на определенный порт, соответствующий классorg.apache.shiro.web.filter.authz.PortFilter

filterChainDefinitionMap = [
    "/**" : "port[9090]" // 如果不是通过9090端口将会重定向至9090端口访问
]

доступhttp://localhost:8080/user/list, порт8080, запрос перехватывается фильтром портов и перенаправляется на9090порт, то естьhttp://localhost:9090/user/list, фильтр портов подходит для совместимости с исходным пользовательским доступом во время изменения порта проекта или автоматического переключения старой версии системы на новую версию (8080 развертывает старую версию, 9090 развертывает новую версию)

3.0.2 SSL-фильтр: ssl

Когда не-https обращается к порту 443, перенаправление использует https для доступа к порту 443. Соответствующий классorg.apache.shiro.web.filter.authz.SslFilter

filterChainDefinitionMap = [
    "/**" : "ssl" // 不可以设置端口号,非https访问443端口会被重定向以https方式访问443端口
]

доступhttp://localhost:456/user/list, из-за доступа по http456порт, запрос перехватывается фильтром портов и перенаправляется наhttps://localhost/user/list(Порты 80 и 443 не отображаются по умолчанию), подходит для пользователей, которым нужен доступ https после добавления SSL-сертификата, и совместим с пользователями, которые изначально использовали доступ http.

3.0.3 ролевой фильтр: roles

Пользователь должен иметь настроенную роль, чтобы иметь доступ. Широ позвонитRealmМетод запроса авторизационной информации в методе получает роль пользователя, соответствующий классorg.apache.shiro.web.filter.authz.RolesAuthorizationFilter

filterChainDefinitionMap = [
    "/**" : "roles['admin,guest']" // 访问用户必须同时具备admin和guest角色才可以访问
]

Если настроить какroles["admin"]представлять до тех пор, покаadminРоль может быть доступна, два или более представителей ролей должны удовлетворять одновременно.

3.0.4 Фильтр разрешений: perms

filterChainDefinitionMap = [
    "/user/add" : "perms['user:add']" // 访问用户必须拥有user模块的add权限
]

Пользователь должен иметь настроенные разрешения для доступа. Широ вызовет метод запроса информации об авторизации в Realm для запроса разрешений пользователя. Соответствующий классorg.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

user:addпредставлятьuserмодульныйaddРазрешения, дизайн разрешений можно разделить на модули и уточнить для каждой функциональной точки модуля.Например, роль администратора в пользовательском (пользовательском) модуле имеет права добавления (добавления) пользователя, удаления (удаления) разрешения пользователя, а база данных может хранить разрешения, принадлежащие администратору.user:add, user:delete, при посещении/user/addПри запросе Широ получит соответствующие разрешения через Realm, если он содержитuser:addВы можете получить доступ к запросу, и доступ запрещен без этого разрешения.

Например, можно использовать только настроенный на уровень модуля в shiro.user:*Выполните проверку подстановочных знаков.perms[user:*:add]Представляет права доступа ко всем подмодулям пользовательского модуля (*соответствуют разрешению на добавление подмодуля)

3.0.5 Фильтр разрешений в стиле REST: rest

Соответствующий классorg.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

filterChainDefinitionMap = [
    // 访问用户必须拥有user模块的对应权限, GET请求代表read
    // 已GET方式的请求必须拥有user:read权限才可以访问
    "/user/*" : "rest[user]" 
]

Соответствие метода запроса операции добавления, удаления, модификации и запроса, когдаPOSTПри доступе к URL в пути фильтр считает, что модуль нужно модифицироватьcreateоперации пользователь должен иметьuser:createРазрешения, разные методы запроса соответствуют разным разрешениям. Детали следующие:

Метод HTTP-запроса Операции, соответствующие Широ Разрешения, которые необходимо предоставить пользователям в системе (в качестве примера возьмем пользовательский модуль)
delete delete user:delete
head read user:read
get read user:read
put update user:update
post create user:create
mkcol create user:create
options read user:read
trace read user:read

Этот фильтр связывает метод HTTP-запроса и разрешения, что можно рассматривать как еще один метод реализации фильтра perms.Поскольку браузеры не дружат с некоторыми методами HTTP-запроса, этот фильтр используется реже.

3.1 Пользовательские фильтры разрешений

Среди вышеперечисленных встроенных фильтров, которые могут поддерживать RBAC,roles, perms, rest, вrolesопределены только роли,perms, restВ правилах также необходимо настроить модули и разрешения в конфигурационном файле Широ.Если система добавляет функции и устанавливает разрешения, конфигурационный файл необходимо изменять синхронно (после модификации необходимо перезапустить Tomcat).Есть ли гибкий способ добавления функций ?Не нужно изменять системный код, обратитесь к следующим идеям:

Все операции в веб-приложениях основаны на URL-адресах, например:/user/addдобавить пользователей,/article/deleteЭто удаление статьи. Если мы установим URL-адрес для роли. Когда пользователь получает доступ к URL-адресу, нам нужно только сравнить, включен ли URL-адрес в набор разрешений, принадлежащий пользователю.

Пример: роль Чжан Сана — менеджер отдела, и он может добавлять пользователей (/user/add) и Изменить пользователя (/user/edit) разрешение, когда Чжан Сан входит в систему для доступа/user/add, После получения полномочий Чжан Саня через Царство URL-адрес (/user/add) в своем списке разрешений Широ разрешает доступ./user/deleteШиро отказывает в доступе, потому что URL-адрес не входит в ее полномочия.

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

У Широ нет встроенного фильтра в таком виде, нам нужно реализовать его самим, и создать новый класс для наследованияAuthorizationFilterпереопределение классаisAccessAllowedМетод.В последующих статьях будет рассказано оisAccessAllowedЭто основной метод фильтра Широ: определить, прошла ли проверка текущего фильтра успешно, и в случае успеха выпустить (контроллер доступа).

  • Фильтр аутентификации: Аутентификация относится к тому, вошел ли он в систему
  • Фильтр авторизации: Аутентификация относится к тому, есть ли у пользователя разрешение на доступ
/**
 * 自定义基于URL的授权过滤器
 * 通过用户访问的URL,从数据库中查询用户是否有访问该URL的权限
 */
public class URLAuthorizationFilter extends AuthorizationFilter {

    /**
     * 是否允许访问资源
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, 
                                      ServletResponse response, 
                                      Object mappedValue) throws Exception {

        // 获取访问的URL
        String requestUrl = WebUtils.toHttp(request).getRequestURI();
        // 判断用户是否有权限访问该URL
        // 调用isPermitted方法时Shiro会通过Realm获取用户拥有的权限集合
        // 并判断URL是否在权限集合中, 如果在权限集合中返回true
        return getSubject(request, response).isPermitted(requestUrl);

    }

}

3.2 Настройка фильтров разрешений

Пользовательские фильтры должны быть определены в Shiro, а URL-адрес конфигурации требует авторизации для доступа.

// 配置自定义过滤器,名称为authz
authz(URLAuthorizationFilter) {
    // 无权限页面: 用户无权限时重定向至该页面
    unauthorizedUrl = "/unauthorized.jsp"
}
// 配置URL规则
// 有请求访问时Shiro会根据此规则找到对应的过滤器处理
filterChainDefinitionMap = [
    "/unauthorized.jsp" : "anon", // 未授权页不需要授权即可访问
    "/logout" : "logout", // 登出使用logout过滤器
    "/login": "authc", // 登录页不配置授权
    "/**": "authc, authz" // 其余所有页面需要认证和授权(顺序:先认证后授权)
]
  • Порядок авторизации и аутентификации, сначала аутентификация, а затем авторизация, если пользователь не вошел в систему, информация о разрешениях, принадлежащая пользователю, не может быть получена (страница входа будет пропущена, когда будет обнаружено, что авторизация не прошла аутентификацию).
  • Страница входа не требует авторизации: authc не будет обрабатывать страницу входа, если она настроена в authz, то будет бесконечный цикл (authz думает, что не авторизовался и перенаправляет на страницу входа)

3.3 Realm получает доступ к разрешениям

Широ необходимо использовать Realm для получения набора разрешений пользователя, поэтому ему необходимо добавить метод для получения разрешений в Realm.

// 自定义查询用户信息的Realm
// 授权需要继承AuthorizingRealm(只认证继承AuthenticatingRealm即可)
public class UserRealm extends AuthorizingRealm {

    // 获取用户权限信息
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 获取当前登录用户的用户名
        // Shiro会将doGetAuthenticationInfo返回的用户信息保存至PrincipalCollection中
        String username = ((User) principals.getPrimaryPrincipal()).getUsername();
        // 模拟数据库查询, 根据用户名查询可以访问的权限URL集合
        Set<String> permSet = getPermissions(username);

        // 将权限URL集合设置至Shiro中,授权时会从此处获取权限URL
        SimpleAuthorizationInfo authz = new SimpleAuthorizationInfo();
        authz.setStringPermissions(permSet);

        return authz;
    }

    // 模拟根据用户名在数据库中查询用户所有的权限URL
    // 数据库中可根据用户找到角色,角色找到资源
    private Set<String> getPermissions(String username) {
        Set<String> permSet = new HashSet<String>();

        // "atd681"有下列页面的访问权限
        if ("atd681".equals(username)) {
            permSet.add("/page/a");
            permSet.add("/page/b");
        }
        // 其他用户有下列页面的访问权限
        else {
            permSet.add("/page/x");
        }

        return permSet;
    }

    // 获取用户信息的方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
        throws AuthenticationException {
       // shiro-认证中的登录逻辑
    }

    // 模拟根据用户名在数据库查询用户信息
    private User getUser(String username) {
        // shiro-认证中的模拟获取用户信息
    }

}
  • Realm, который получает информацию об авторизации, должен наследовать AuthorizingRealm и реализовать метод doGetAuthorizationInfo.
  • При получении разрешений найдите ресурсы (доступные URL-адреса), принадлежащие пользователю в соответствии с отношением (пользователь>роль>ресурс)
  • Вам необходимо установить полученный набор разрешений (Set) в класс SimpleAuthorizationInfo и вернуть его Широ
  • В этом примере пользователь atd681 может получить доступ к страницам a и b, но не может получить доступ к странице x.

4. Тест

запустите проект, используйтеatd681Доступ отдельно после авторизации/page/aи/page/b

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

5. Просмотр разрешений на управление слоями

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

  • Когда у пользователя нет разрешения, ссылка или кнопка не может быть доступна после нажатия, и взаимодействие с пользователем плохое.
  • Открывает URL-адрес этой функции системы, вызывая ненужные угрозы безопасности.

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

Широ предоставляет нам набор тегов, которые могут судить об аутентификации или авторизации в JSP. Добавьте следующий код в JSP /page/a:

Добавьте ссылку на тег Shiro в заголовок JSP.

<%@ tagliburi ="http://shiro.apache.org/tags" prefix="shiro"%>

используется в JSPshiro:hasPermissionУправляет отображением ссылок или кнопок в зависимости от разрешений пользователя.

<body>
	系统菜单:
	
	<!-- 
		该标签根据name值判断当前用户是否有该页面的访问权限
		无权限时不显示该链接(调用subject.isPermitted方法进行验证)
	 -->
	<shiro:hasPermission name="/page/a">
		<a href="/page/a">A</a>
	</shiro:hasPermission>
	<shiro:hasPermission name="/page/b">
		<a href="/page/b">B</a>
	</shiro:hasPermission>
	<shiro:hasPermission name="/page/x">
		<a href="/page/x">X</a>
	</shiro:hasPermission>
	
	
	<br> PAGE_A, 当前登录用户ID: ${userId}, 用户名: ${userName}

	<a href="/logout">登出</a>
</body>
  • <shiro:hasPermission>серединаnameАтрибут представляет собой URL-адрес ссылки, чтобы определить, есть ли у пользователя разрешение на доступ к URL-адресу.
  • только тогда, когда<shiro:hasPermission>возвращениеtrue, внутри этикеткиHTMLбудет возвращено клиенту
  • Код реализации всех тегов находится вorg.apache.shiro.web.tagsВ каталоге, если интересно, можете проверить сами

запустите проект, используйтеatd681Доступ после авторизации/page/a, потому что пользовательatd681иметь доступ/page/aи/page/bРазрешения, отображаются ссылки A, B. Без разрешения на доступ к /page/x ссылка X не отображается.

6. Пример кода

На данный момент пример конфигурации на основе авторизации Широ завершен, заинтересованные студенты могут создать еще несколько пользователей для тестирования.