在SpringBoot中的AuthenticationSuccessHandler中进行服务的字段注入。

huangapple go评论74阅读模式
英文:

Field injection of a service in AuthenticationSuccessHandler in SpringBoot

问题

在我的应用程序中,我有一个Account类,它还实现了UserDetails接口。我还创建了一个名为MyAuthenticaionSuccessHandler的类,它扩展了SimpleUrlAuthenticationSuccessHandler类。我想要的是在用户登录后更改Account类中的dateLastLogin字段。在onAuthenticationSuccess方法中,我想要一个AccountService的实例,其中存在save(Account account)方法,以将更新后的Account保存到数据库中。问题开始出现在这里。我不能进行字段注入,因为我必须在构造函数中初始化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; // <-- 这里不起作用

    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);
    }
}

希望这些信息对您有所帮助。如果您有任何其他问题,请随时提问。

英文:

in my app I have an Account class which also implements UserDetails. I also created class MyAuthenticaionSuccessHandler which extends SimpleUrlAuthenticationSuccessHandler. What I want is to change a field dateLastLogin on Account after user logs in. In method onAuthenticationSuccess I want instance of AccountService in which method save(Account account) exist, to save updated Account to db. The problem begins here. I can't do field injection, because I have to initialize an instance of AccountService in constructor. I can't do that, because then I won't be able to create an instance of MyAuthenticaionSuccessHandler. I also can't create it manually. Instances of other classes like services or controllers in which instances of other service/repository classes are created automatically, so there it works. But how to make it work for custom authentication success handler?<br>
Here are pieces of my code:<br>

Piece of class that extends WebSecurityConfigureAdapter

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

Piece of 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);
    }
// ...

And my own authentication success handler

public class MyAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    private final AccountService accountService; // &lt;-- here it doesn&#39;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);
    }
}

答案1

得分: 1

在Spring应用程序中,不应直接使用new关键字来创建对象。你可以通过使用@Bean注解来创建一个Bean,然后使用@Autowired注解进行自动装配。

@Configuration
public class AppConfiguration() {

  @Bean
  public MyAuthenticationSuccessHandler myAuthenticationSuccessHandler (){
    return new MyAuthenticationSuccessHandler("/user/overview");
  }
}
@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
英文:

You should not use new to create an object directly in a spring application. What you can do is create a bean using @Bean annotation and autowire it using @Autowired annotation.

@Configuration
public class AppConfiguration() {

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

---

@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

答案2

得分: 0

我在查看您的代码时并没有看到不能将 AccountService 注入到 MyAuthenticationSuccessHandler 中的任何原因。如果您发布的代码确实是您的确切代码,那么问题出在以下部分:

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

因为在这里使用了 new,这使得Spring完全不参与其中,因此没有将任何内容注入到 MyAuthenticationFailureHandler 中。

在您的 WebSecurityConfigureAdapter 中,尝试添加一个成员变量:

@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

然后,在您的链中像这样添加它:

.successHandler(myAuthenticationSuccessHandler)

如果您绝对需要在此bean构造函数中传递参数(URL),那么您将需要创建一个BeanFactory,用于生成类型为 MyAuthenticationSuccessHandler 的Spring bean,其中包含您的URL。

英文:

In looking at your code I don't see any reason why you cannot inject AccountService into MyAuthenticationSuccessHandler. If the code you've posted is your exact code, then the problems lies in

.successHandler(new MyAuthenticationSuccessHandler(&quot;/user/overview&quot;))

because by using new here, you've taken Spring completely out of the equation and aren't getting any injections into MyAuthenticationFailureHandler.

In your WebSecurityConfigureAdapter try adding a member variable

@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

then, in your chain, add it like so

.successHandler(myAuthenticationSuccessHandler)

If you absolutely must have parameters in this bean constructor (the url), then you'll need to create a BeanFactory that produces a Spring bean of type MyAuthenticationSuccessHandler that contains your url.

huangapple
  • 本文由 发表于 2020年8月6日 10:03:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/63275855.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定