Я использую Spring Boot Data REST для сопоставления репозиториев объектов Hibernate с маршрутами REST. Я также использую аннотацию Spring Security @PreAuthorize
для защиты определенных методов этих репозиториев. Это отлично работает во время производства, но когда я хочу программно инициализировать репозитории данными (например, добавить первого пользователя для начала работы и некоторые другие образцы данных), он жалуется, что «Объект аутентификации не был найден в SecurityContext». Я понимаю, что это связано с тем, что во время настройки базы данных в контексте безопасности нет аутентифицированного пользователя (с автосвязанным компонентом, сохраняющим объекты в репозитории). Однако я хотел бы временно обойти эту авторизацию во время настройки, чтобы я мог инициализировать базу данных.
Есть ли способ добиться этого? А если нет, то как вручную войти в метод инициализации? Я видел несколько попыток второго подхода, но все они требуют доступа к AuthenticationManager
, который я не знаю, как получить.
Как вы добавляете исходные данные? Через РЕСТ? Если да, то почему REST, а не что-то вроде liquebase?
Я добавляю исходные данные через @Component с помощью repository.save
(так что программно)
@Prasath Я действительно добавляю суперпользователя в этот компонент настройки. Однако я бы предпочел делать это не в SQL, а в Java-коде, если это возможно.
Мы можем сделать обходной путь. Жестко закодируйте одну пользовательскую запись и сохраните ее при запуске сервера. Сделайте этот жесткий код из класса обслуживания с помощью некоторого метода с @postconstruct.
Спасибо за предложение! К сожалению, методы класса службы с @PostConstruct не выполняются до запуска службы безопасности Spring. Я получаю ту же ошибку, когда пытаюсь поместить инициализацию в такой метод.
Что-то называется в памяти аутентификацией. Попробуй это. Это может сработать для case.memorynotfound.com/…
Спасибо за ссылку! Я думал об этом, и мне, возможно, придется прибегнуть к этому в конце для целей тестирования, но мне бы очень хотелось добиться этого с помощью постоянной аутентификации... Это означало бы меньше модификаций для тестов (поэтому более реалистичные тесты ) и более легкое развертывание в дальнейшем.
Это работает?
Честно говоря, это не то, что я искал. Я ценю это предложение, но я действительно не хочу менять метод аутентификации. Я просто хотел бы временно отключить авторизацию глобального метода, пока я добавляю объекты, а затем снова включить его...
Моя главная цель действительно состоит в том, чтобы инициализировать базу данных с пользователем и некоторыми другими необходимыми базовыми данными.
Простое решение: игнорировать безопасность и сосредоточиться на пустом репозитории.
@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()
будет вызываться, даже если пользователя нет.
Вы можете использовать следующие коды, чтобы создать фальшивого пользователя, у которого достаточно прав, и установить для него 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();
Там должен быть хотя бы один суперпользователь. У него должны быть все права доступа. Мы можем поместить запись при запуске сервера, используя некоторые сценарии SQL в расположении ресурсов.