5

试图了解使用 Spring Security 实现 OpenID 身份验证的正确方法是什么。

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) {
    ...
  }
}

我正在考虑用户尚未在我的应用程序中注册的情况。要注册用户,我需要知道其 OpenID 和电子邮件。

当 OpenID 提供程序将用户重定向回我的应用程序时,loadUserByUsername()会调用它,但在这种情况下,我只知道用户的 OpenID。所以,我在抛出UsernameNotFoundException然后loadUserDetails()永远不会被调用,所以我无法注册用户。

这里的常见解决方案是什么?如果我返回类似FakePartialUserDetailsfromloadUserByUsername()然后,当loadUserDetails()被调用时,我注册用户然后返回 realMyCustomUserDetails怎么办?

我正在使用 Spring Security 3.0.7.RELEASE

4

2 回答 2

1

这很有趣,但通过迁移到Spring Security 3.1.0.RELEASE设法解决了这个问题。

对于相同的场景,行为是完全不同的——loadUserByUsername()不被loadUserDetails()调用,而是被调用。

于 2012-06-07T08:09:39.123 回答
0

我通过实施解决了同样的情况

AuthenticationUserDetailsService<OpenIDAuthenticationToken>

在我的 UserDetailsS​​ervice 中。

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

}

只需确保在配置 openid-form 时将上述服务用作 UserDetailsS​​ervice。此外,在配置 openid 时为“电子邮件”属性配置属性交换。然后可以从“OpenIDAuthenticationToken”中获取成功认证后返回的电子邮件,该电子邮件最终作为参数传递给 loadUserByUsername 函数。

如果您有用户使用该电子邮件注册,则身份验证已完成。否则,您可以建议用户通过该电子邮件注册或显示登录失败页面。

于 2013-05-15T17:44:52.667 回答