Spring Security 在登录失败时返回 String 作为主体而不是 UserDetails?

Posted

技术标签:

【中文标题】Spring Security 在登录失败时返回 String 作为主体而不是 UserDetails?【英文标题】:Spring security returns String as principal instead of UserDetails on failed login? 【发布时间】:2013-07-01 10:48:48 【问题描述】:

要么我遗漏了一些东西,要么这就是它的工作原理...... 即,我实现了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 实例,对于这种情况。 想法?

【问题讨论】:

【参考方案1】:

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

在典型情况下,这将是 UsernamePasswordAuthenticationToken,其中“主要”属性是提交的用户名。

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

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

【讨论】:

所以,这实际上是它应该的方式......?我已经在使用AuthenticationSuccessHandler 进行计数器重置,不知道这是否是正确的方法,我没有想到尝试使用AuthenticationFailureHandler 是的,应该是这样的。该事件表示“这是失败的身份验证请求”,并且身份验证请求仅包含用户的字符串标识符。

以上是关于Spring Security 在登录失败时返回 String 作为主体而不是 UserDetails?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot + Spring Security Restful 登录

Spring Security 多个登录用户失败

使用 Spring Security 登录失败

返回用户名和密码以登录表单grails spring security

Spring Security 自定义登录认证

为什么Spring Security看不见登录失败或者注销的提示