简体   繁体   中英

Spring security returns String as principal instead of UserDetails on failed login?

Either I'm missing something, or this is how it works...
Namely, I implemented UserDetailsService , and sub-classed ( AppUser below) spring utility class User , (that implements UserDetails ). If it matters, it goes something like this:

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

Then I tried to implement account locking using this approach:

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 ?
    // ...
}
}

However, I ran into java.lang.ClassCastException while trying to get the principal object from the supplied event argument (principal object was of type String ). I mean, OK - I can just load my SystemUser by username again, to solve the problem, but I did not expect this...
I think that even the source documentation states that getPrincipal() should return UserDetails instance, for this scenario.
Thoughts?

Since we are dealing with an authentication failure, the Authentication object in the event is the one which was submitted to the AuthenticationManager (and which was rejected).

In a typical scenario this would be a UsernamePasswordAuthenticationToken where the "principal" property is the submitted username.

The AuthenticationManager supports lots of different authentication mechanisms and, from its perspective, there's no guarantee that a UserDetailsService is even involved in the authentication. All it knows is that the authentication token was not accepted (there was an exception) and it publishes the event accordingly.

Alternative options are to customize the AuthenticationProvider in use or plug in an AuthenticationFailureHandler (if you're using form-login, for example) and do the extra work in there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM