Spring Security OpenID - UserDetailsService, AuthenticationUserDetailsService

99封情书 提交于 2019-12-10 15:32:49

问题


Trying to understand what's the correct way of implementing OpenID authentication with Spring Security.

public class OpenIDUserDetailsService implements 
  UserDetailsService, 
  AuthenticationUserDetailsService {

  @Override
  public UserDetails loadUserByUsername(String openId) throws
    UsernameNotFoundException, DataAccessException {

    // I either want user email here
    // or immediately delegate the request to loadUserDetails

  }

  @Override
  public UserDetails loadUserDetails(Authentication token) throws
    UsernameNotFoundException {

    // This never gets called if I throw from loadUserByUsername()

  }

  private MyCustomUserDetails registerUser(String openId, String email) {
    ...
  }
}

I'm considering the scenario when user is not yet registered within my application. To register the user, I need to know its OpenID and email.

When OpenID provider redirects the user back to my application, loadUserByUsername() is called, but in this case I'm only aware about user's OpenID. So, I'm throwing UsernameNotFoundException and then loadUserDetails() never gets called, so I can't register user.

What's the common solution here? What if I return something like FakePartialUserDetails from loadUserByUsername() and then, when loadUserDetails() is called, I register the user and then return the real MyCustomUserDetails?

I'm using Spring Security 3.0.7.RELEASE


回答1:


That's funny, but managed to resolve it by moving to Spring Security 3.1.0.RELEASE.

For the same scenario, behavior is absolutely different - loadUserByUsername() is not called and loadUserDetails() is called instead.




回答2:


I solved the same situation by implementing

AuthenticationUserDetailsService<OpenIDAuthenticationToken>

in my UserDetailsService.

public class OpenIdUserDetailsService implements UserDetailsService,
    AuthenticationUserDetailsService<OpenIDAuthenticationToken> {

@Autowired(required = true)
@Qualifier(value = "jdbcUserDetailsService")
private UserDetailsService localUserDetailsService;

/**
 * @return the localUserDetailsService
 */
public UserDetailsService getLocalUserDetailsService() {
    return localUserDetailsService;
}

/**
 * @param localUserDetailsService
 *            the localUserDetailsService to set
 */
public void setLocalUserDetailsService(
        UserDetailsService localUserDetailsService) {
    this.localUserDetailsService = localUserDetailsService;
}

@Override
public UserDetails loadUserDetails(OpenIDAuthenticationToken token)
        throws UsernameNotFoundException {
    String email = getEmail(token);
    return loadUserByUsername(email);
}

@Override
public UserDetails loadUserByUsername(String username)
        throws UsernameNotFoundException {
    return localUserDetailsService.loadUserByUsername(username);
}

private String getEmail(OpenIDAuthenticationToken token) {
    for (OpenIDAttribute attribute : token.getAttributes()) {
        if (attribute.getName().equals("email")) {
            return attribute.getValues().get(0);
        }
    }
    return null;
}

}

Just make sure to use above service as the UserDetailsService while configuring openid-form. Also, configure attribute exchange for 'email' attribute while configuring openid. The email returned after successfull authentication can then be fetched from 'OpenIDAuthenticationToken' which eventually gets passed as paramter to loadUserByUsername function.

If you have user registered with that email, authentication is complete. Else you can suggest user to get registered by that email or show login failure page.



来源:https://stackoverflow.com/questions/10927633/spring-security-openid-userdetailsservice-authenticationuserdetailsservice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!