要么我错过了什么,要么就是它的工作原理......
也就是说,我实现了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<AuthenticationFailureBadCredentialsEvent> {
// 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
实例,对于这种情况
想法?
答案 0 :(得分:5)
由于我们正在处理身份验证失败,因此事件中的Authentication
对象是提交给AuthenticationManager
的对象(并被拒绝)。
在典型情况下,这将是UsernamePasswordAuthenticationToken
,其中“principal”属性是提交的用户名。
AuthenticationManager
支持许多不同的身份验证机制,从它的角度来看,无法保证UserDetailsService
甚至可以参与身份验证。它只知道身份验证令牌未被接受(存在异常)并且相应地发布事件。
备选方案是自定义正在使用的AuthenticationProvider
或插入AuthenticationFailureHandler
(例如,如果您正在使用表单登录)并在那里执行额外的工作。