Spring安全性返回String作为主体而不是登录失败时的UserDetails?

要么我错过了什么,要么它是如何工作的……
也就是说,我实现了UserDetailsService和子类(下面的AppUser )spring实用程序类User (实现UserDetails )。 如果重要,它会是这样的:

 @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // try loading user by its name SystemUser user = null; try { user = this.sysUserService.getByUsername(username); if(user == null) throw new UsernameNotFoundException("User not found!"); } catch(Exception e) { throw new DataRetrievalFailureException( "Could not load user with username: " + username); } // load user rights, and create UserDetails instance UserDetails res = new AppUser(user, getUserAuthorities(user)); return res; } 

然后我尝试使用这种方法实现帐户锁定:

 public class LoginFailureEventListenter implements ApplicationListener { // rest omitted for brevity @Override public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) { // ... SystemUser user = ((AppUser)event.getAuthentication().getPrincipal()).getSystemUser(); // cast exception - how is it possible to obtain String // instead of UserDetails object here ? // ... } } 

但是,在尝试从提供的事件参数中获取主体对象时,我遇到了java.lang.ClassCastException (主体对象的类型为String )。 我的意思是,好的 – 我可以再次通过用户名加载我的SystemUser来解决问题,但我没想到这个……
我认为即使是源文档也声明getPrincipal()应该为此场景返回UserDetails实例。
思考?

由于我们正在处理身份validation失败,因此事件中的Authentication对象是提交给AuthenticationManager (并且被拒绝)的对象。

在典型的场景中,这将是UsernamePasswordAuthenticationToken ,其中“principal”属性是提交的用户名。

AuthenticationManager支持许多不同的身份validation机制,从它的角度来看,不能保证UserDetailsService甚至参与身份validation。 它只知道身份validation令牌未被接受(存在exception)并且相应地发布事件。

替代选项是自定义正在使用的AuthenticationFailureHandler或插入AuthenticationFailureHandler (例如,如果您正在使用表单登录)并在那里执行额外的工作。