Реализация ролевой авторизации в Spring Boot с помощью Keycloak

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

В предыдущей статье мы узнали, как защитить наш Spring Boot REST API с помощью Keycloak, используя протокол аутентификации OpenID Connect.

В этой статье мы собираемся развить этот пример приложения и добавить авторизацию на основе ролей.

Цель состоит в том, чтобы разрешить доступ к некоторым конечным точкам только пользователям с определенной ролью. Точнее, мы собираемся ограничить доступ к конечной точке DELETE только пользователям с ролью администратора.

Добавление новой конечной точки

Давайте сначала расширим наш Spring Controller, добавив новую конечную точку DELETE.

package com.mozen.springbootkeycloack.controller;

import com.mozen.springbootkeycloack.model.Plant;
import com.mozen.springbootkeycloack.service.PlantService;
import com.sun.istack.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController()
@RequestMapping("/plant")
public class PlantController {

        ...

    @DeleteMapping("/{plantId}")
    public void deletePlant(@PathVariable long plantId) {

        log.info("Delete plant request for plant " + plantId + " received");

        plantService.deletePlant(plantId);
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Расширение конфигурации

Возвращаясь к файлу application.yml, мы указываем новое свойство для конфигурации Keycloak.

...

keycloak:
    ...
  use-resource-role-mappings: false

Войти в полноэкранный режим Выйти из полноэкранного режима

Мы устанавливаем свойство use-resource-role-mappings в false.

Это означает, что авторизация будет основана на ролях уровня царства Keycloak, а не на клиентских ролях, специфичных для приложения Spring Boot.

Мы делаем это потому, что используемая нами по умолчанию роль администратора Keycloak определена как роль уровня царства.

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

Нам также необходимо внести небольшие изменения в WebSecurityConfiguration..

@KeycloakConfiguration
public class WebSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider =
                keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new NullAuthenticatedSessionStrategy();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.csrf()
                .disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.DELETE,"/plant/**")
                .hasRole("admin")
                .anyRequest()
                .authenticated()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Мы добавляем новый antMatcher, который ограничивает все маршруты, начинающиеся с ‘/plant/’ и использующие метод HTTP DELETE, что соответствует конечной точке deletePlant, которую мы добавили ранее.

Обратите внимание, что сопоставление ролей осуществляется с помощью SimpleAuthorityMapper. По умолчанию Spring Security добавляет префикс ‘ROLE_’ к любому полномочию, но роли Keycloak этого не делают.

При использовании этого маппера префикс будет добавлен к любому полномочию, отправленному в токене Keycloak, если его еще нет.

Настройка Keycloak

У нас уже есть пользователь ‘admin’ из предыдущей статьи. Этот пользователь уже имеет роль ‘admin’.

Нам нужно создать нового пользователя, не имеющего роли администратора.

Он будет использоваться для демонстрации того, что наша авторизация на основе ролей работает и что конечная точка DELETE будет запрещена для этого пользователя.

Тестирование приложения

Давайте сначала запустим наше приложение.


mvn spring-boot:run

Вход в полноэкранный режим Выход из полноэкранного режима

Для тестирования нашей установки мы будем использовать тот же метод, что и в предыдущей статье, и использовать Postman в роли клиента.

Мы улучшим нашу конфигурацию Postman, добавив нового пользователя в коллекцию переменных

Давайте сначала убедимся, что «пользователь» без роли администратора не может получить доступ к конечной точке удаления.

Сначала мы получим токен с помощью пользователя без роли администратора.

И попробуем воспользоваться конечной точкой удаления, предоставив этот токен в заголовке авторизации.

Как и ожидалось, мы получаем ошибку 401 Unauthorized, поскольку роль администратора отсутствует.

На этот раз мы получаем обратно новый токен с пользователем admin.

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

Вот и все! Теперь у нас есть ролевая авторизация.

Обратите внимание, что начиная с версии 5.7.0 Spring Security, WebSecurityConfigurerAdapter устарел. Теперь рекомендуется использовать новый тип конфигурации, следуя компонентно-ориентированному дизайну. На данный момент Keycloak Spring Boot Adapter не поддерживает этот новый тип конфигурации. Я постараюсь обновить эту статью для поддержки этого нового типа конфигурации как можно скорее.

Вы можете получить доступ к демонстрационному проекту для этой статьи блога здесь https://github.com/Mozenn/spring-boot-keycloak-roles.

Оцените статью
devanswers.ru
Добавить комментарий