Внедрение поля службы в AuthenticationSuccessHandler в SpringBoot - PullRequest
0 голосов
/ 06 августа 2020

в моем приложении у меня есть класс Account, который также реализует UserDetails. Я также создал класс MyAuthenticaionSuccessHandler, который расширяет SimpleUrlAuthenticationSuccessHandler. Я хочу изменить поле dateLastLogin на Account после входа пользователя в систему. В методе onAuthenticationSuccess мне нужен экземпляр AccountService, в котором существует метод save(Account account), чтобы сохранить обновленный Account в db. Проблема начинается здесь. Я не могу выполнить внедрение поля, потому что мне нужно инициализировать экземпляр AccountService в конструкторе. Я не могу этого сделать, потому что тогда я не смогу создать экземпляр MyAuthenticaionSuccessHandler. Я тоже не могу создать его вручную. Экземпляры других классов, таких как службы или контроллеры, в которых экземпляры других классов службы / репозитория создаются автоматически, поэтому там это работает. Но как заставить его работать для пользовательского обработчика успешной аутентификации?
Вот фрагменты моего кода:

Часть класса, расширяющая WebSecurityConfigureAdapter

// ...
   .formLogin()
        .loginPage("/guest/login")
        .permitAll()
        .failureHandler(new MyAuthenticationFailureHandler("/guest/login"))
        .successHandler(new MyAuthenticationSuccessHandler("/user/overview"))
        .and()
    .logout()
//  ...

Часть AccountService

@Service
@Transactional
public class AccountService implements UserDetailsService {
    private final AccountRepository accountRepository;
    private final ActivationCodeService activationCodeService;
    public AccountService(AccountRepository accountRepository, ActivationCodeService activationCodeService) {
        this.accountRepository = accountRepository;
        this.activationCodeService = activationCodeService;
    }

    public void saveAccount(Account account){
        accountRepository.save(account);
    }
// ...

И мой собственный обработчик успешной аутентификации

public class MyAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    private final AccountService accountService; // <-- here it doesn't work

    public MyAuthenticationSuccessHandler() {
    }

    public MyAuthenticationSuccessHandler(String defaultTargetUrl) {
        super(defaultTargetUrl);
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        super.onAuthenticationSuccess(request, response, authentication);
        Account account = (Account)authentication.getPrincipal();
        account.setDateLastLogin(new Date());
        accountService.saveAccount(account);
    }
}

Ответы [ 2 ]

1 голос
/ 06 августа 2020

Вы не должны использовать new для создания объекта непосредственно в приложении Spring. Что вы можете сделать, так это создать bean-компонент с помощью аннотации @Bean и автоматически связать его с помощью аннотации @Autowired.

@Configuration
public class AppConfiguration() {

  @Bean
  public MyAuthenticationSuccessHandler myAuthenticationSuccessHandler (){
  return new MyAuthenticationSuccessHandler("/user/overview");
  }
}

---

@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
0 голосов
/ 06 августа 2020

Глядя на ваш код, я не вижу причин, по которым вы не можете вставить AccountService в MyAuthenticationSuccessHandler. Если опубликованный вами код является вашим точным кодом, тогда проблема заключается в

.successHandler(new MyAuthenticationSuccessHandler("/user/overview"))

, потому что, используя здесь new, вы полностью исключили Spring из уравнения и не получают никаких инъекций в MyAuthenticationFailureHandler.

В вашем WebSecurityConfigureAdapter попробуйте добавить переменную-член

@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

, затем в своей цепочке добавьте ее так

.successHandler(myAuthenticationSuccessHandler)

Если вам абсолютно необходимы параметры в этом конструкторе bean-компонентов (url-адрес), тогда вам потребуется создать BeanFactory, который будет создавать bean-компонент Spring типа MyAuthenticationSuccessHandler, содержащий ваш url-адрес.

...