«1. Обзор

В этой быстрой статье мы объясним тонкую, но существенную разницу между ролью и предоставленным полномочием в Spring Security. Подробнее о ролях и полномочиях см. в статье здесь.

2. GrantedAuthority

В Spring Security мы можем думать о каждом GrantedAuthority как об отдельной привилегии. Примеры могут включать READ_AUTHORITY, WRITE_PRIVILEGE или даже CAN_EXECUTE_AS_ROOT. Важно понимать, что имя произвольное.

При непосредственном использовании GrantedAuthority, например, с помощью выражения hasAuthority(“READ_AUTHORITY”), мы ограничиваем доступ на более тонкой основе.

Как вы, наверное, уже поняли, мы можем ссылаться на понятие авторитета и с помощью привилегий.

3. Роль как полномочие

Точно так же в Spring Security мы можем думать о каждой роли как о крупнозернистом GrantedAuthority, представленном в виде строки с префиксом «ROLE». При непосредственном использовании роли, например, с помощью выражения типа hasRole(\»ADMIN\»), мы ограничиваем доступ в грубой манере.

Стоит отметить, что префикс «ROLE» по умолчанию настраивается, но объяснение того, как это сделать, выходит за рамки этой статьи.

Основное различие между ними заключается в семантике, которую мы придаем тому, как мы используем эту функцию. Для фреймворка разница минимальна — и он в основном работает с ними точно так же.

4. Роль как контейнер

Теперь, когда мы увидели, как фреймворк использует концепцию ролей, давайте также быстро обсудим альтернативу — использование ролей в качестве контейнеров полномочий/привилегий.

Это подход более высокого уровня к ролям, делающий их концепцией, более ориентированной на бизнес, а не на реализацию.

Фреймворк Spring Security не дает никаких указаний относительно того, как мы должны использовать эту концепцию, поэтому выбор полностью зависит от реализации.

5. Конфигурация безопасности Spring

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

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

Давайте настроим такой сценарий в нашей конфигурации безопасности:

@Override
protected void configure(HttpSecurity http) throws Exception {
    // ...
    .antMatchers("/protectedbyrole").hasRole("USER")
    .antMatchers("/protectedbyauthority").hasAuthority("READ_PRIVILEGE")
    // ...
}

6. Простая инициализация данных

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

Это, конечно, очень простой способ сделать это, чтобы взяться за дело с некоторыми предварительными тестовыми пользователями во время разработки — не так, как вы должны обрабатывать данные в рабочей среде.

Мы собираемся прослушивать событие обновления контекста:

@Override
@Transactional
public void onApplicationEvent(ContextRefreshedEvent event) {
    MyPrivilege readPrivilege
      = createPrivilegeIfNotFound("READ_PRIVILEGE");
    MyPrivilege writePrivilege
      = createPrivilegeIfNotFound("WRITE_PRIVILEGE"); 
}

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

7. UserDetailsService

В нашей реализации UserDetailsService происходит сопоставление полномочий. После аутентификации пользователя наш метод getAuthorities() заполняет и возвращает объект UserDetails:

private Collection<? extends GrantedAuthority> getAuthorities(
  Collection<Role> roles) {
    List<GrantedAuthority> authorities
      = new ArrayList<>();
    for (Role role: roles) {
        authorities.add(new SimpleGrantedAuthority(role.getName()));
        role.getPrivileges().stream()
         .map(p -> new SimpleGrantedAuthority(p.getName()))
         .forEach(authorities::add);
    }
    
    return authorities;
}

8. Запуск и тестирование примера

Мы можем выполнить пример Java-приложения RolesAuthoritiesApplication, найденный в проекте GitHub.

Чтобы увидеть авторизацию на основе ролей в действии, нам необходимо:

    Доступ к http://localhost:8082/protectedbyrole Авторизация как [email protected] (пароль «user») Отметить успешную авторизацию Доступ к http: //localhost:8082/protectedbyauthority Обратите внимание на неудачную авторизацию

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

    Зайти на http://localhost:8082/protectedbyauthority Авторизоваться как [email protected] / admin Отметить успешную авторизацию Доступ http://localhsot:8082/protectedbyrole Отметить неудачную авторизацию

9. Заключение

«В этом кратком руководстве мы рассмотрели тонкую, но существенную разницу между ролью и GrantedAuthority в Spring Security.