Инициализировать репозитории, защищенные аутентификацией Spring

Я использую Spring Boot Data REST для сопоставления репозиториев объектов Hibernate с маршрутами REST. Я также использую аннотацию Spring Security @PreAuthorize для защиты определенных методов этих репозиториев. Это отлично работает во время производства, но когда я хочу программно инициализировать репозитории данными (например, добавить первого пользователя для начала работы и некоторые другие образцы данных), он жалуется, что «Объект аутентификации не был найден в SecurityContext». Я понимаю, что это связано с тем, что во время настройки базы данных в контексте безопасности нет аутентифицированного пользователя (с автосвязанным компонентом, сохраняющим объекты в репозитории). Однако я хотел бы временно обойти эту авторизацию во время настройки, чтобы я мог инициализировать базу данных.

Есть ли способ добиться этого? А если нет, то как вручную войти в метод инициализации? Я видел несколько попыток второго подхода, но все они требуют доступа к AuthenticationManager, который я не знаю, как получить.

Там должен быть хотя бы один суперпользователь. У него должны быть все права доступа. Мы можем поместить запись при запуске сервера, используя некоторые сценарии SQL в расположении ресурсов.

Prasath 27.05.2019 11:23

Как вы добавляете исходные данные? Через РЕСТ? Если да, то почему REST, а не что-то вроде liquebase?

alexey28 27.05.2019 11:47

Я добавляю исходные данные через @Component с помощью repository.save (так что программно)

gandreadis 27.05.2019 11:50

@Prasath Я действительно добавляю суперпользователя в этот компонент настройки. Однако я бы предпочел делать это не в SQL, а в Java-коде, если это возможно.

gandreadis 27.05.2019 13:31

Мы можем сделать обходной путь. Жестко закодируйте одну пользовательскую запись и сохраните ее при запуске сервера. Сделайте этот жесткий код из класса обслуживания с помощью некоторого метода с @postconstruct.

Prasath 27.05.2019 14:13

Спасибо за предложение! К сожалению, методы класса службы с @PostConstruct не выполняются до запуска службы безопасности Spring. Я получаю ту же ошибку, когда пытаюсь поместить инициализацию в такой метод.

gandreadis 27.05.2019 15:05

Что-то называется в памяти аутентификацией. Попробуй это. Это может сработать для case.memorynotfound.com/…

Prasath 27.05.2019 20:46

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

gandreadis 28.05.2019 07:43

Это работает?

Prasath 29.05.2019 07:02

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

gandreadis 29.05.2019 09:19
" добавление первого пользователя для начала работы и некоторые другие примеры данных " это ваша главная (единственная) цель?
Dirk Deyne 30.05.2019 12:57

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

gandreadis 30.05.2019 17:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
12
638
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Простое решение: игнорировать безопасность и сосредоточиться на пустом репозитории.

@Component
class InitializeDataIfNoDataPresent {
  private final UserRepo repository;

  public InitializeDataIfNoDataPresent(UserRepo repo) {
      this.repository = repo;
  }

  @EventListener(ApplicationReadyEvent.class)
  public void init() {
    if (0 == repository.count()) {
      setupData();
    } 
  }

  @PreAuthorize("hasRole('ADMIN')")
  public void setupData() {
    // your existing setup
  }

}

Когда приложение запускается и ваш репозиторий пуст, setupData() будет вызываться, даже если пользователя нет.

ссылка: stackoverflow-инициализация-защищенный

Ответ принят как подходящий

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

List<GrantedAuthority> grantedAuthorities = new ArrayList<>();

//Setup the permission that the user should have in order to run that method.
//It is the customized value based on your security configuration
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN")); 

//Ensure this user is enabled , active and has above permission
User user = new User("admin", "password", true, true, true, true, grantedAuthorities);

Authentication auth = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);

После выполнения этого защищенного метода сбросьте SecurityContext (что эквивалентно выходу из системы):

SecurityContextHolder.clearContext();

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