2012-06-07 15 views
5

Próba zrozumienia, jaki jest prawidłowy sposób implementacji uwierzytelniania OpenID w Spring Security.Spring Security OpenID - UserDetailsService, AuthenticationUserDetailsService

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

Rozważam scenariusz, gdy użytkownik nie jest jeszcze zarejestrowany w mojej aplikacji. Aby zarejestrować użytkownika, muszę znać jego identyfikator OpenID i adres e-mail.

Gdy dostawca OpenID przekierowuje użytkownika z powrotem do mojej aplikacji, wywoływana jest nazwa loadUserByUsername(), ale w tym przypadku mam świadomość tylko tego, że OpenID użytkownika. Tak więc rzucam UsernameNotFoundException, a następnie loadUserDetails() nigdy nie zostanie wywołany, więc nie mogę zarejestrować użytkownika.

Jakie jest wspólne rozwiązanie? Co się stanie, jeśli zwrócę coś w rodzaju FakePartialUserDetails z loadUserByUsername(), a następnie, gdy zostanie wywołana loadUserDetails(), zarejestruję użytkownika, a następnie zwrócę rzeczywistą wartość MyCustomUserDetails?

Używam Wiosna Zabezpieczenia 3.0.7.RELEASE

Odpowiedz

1

To zabawne, ale udało się go rozwiązać, przenosząc do Wiosna Bezpieczeństwa 3.1.0.RELEASE.

Z tego samego scenariusza, zachowanie jest absolutnie inny - loadUserByUsername() nie nazywa i loadUserDetails() nazywa zamiast.

+4

To nie jest poprawne. W wersji 3.1 narzędzie OpenIDAuthenticationProvider ma ustawione opcje dla usługi UserDetailsService i AuthenticationUserDetailsService i wywołuje metodę loadUserByUsername lub loadUserDetails w zależności od używanego programu ustawiającego. W wersji 3.0.7 program uwierzytelniającyUserDetailsService nie był ustawiony i dlatego zawsze używał loadUserByUsername. – Ritesh

0

I rozwiązać samą sytuację poprzez wdrożenie

AuthenticationUserDetailsService<OpenIDAuthenticationToken> 

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

} 

Pamiętaj tylko, aby użyć powyższej usługi jako UserDetailsService podczas konfigurowania formularza openid. Ponadto skonfiguruj wymianę atrybutów dla atrybutu "email" podczas konfigurowania obiektu openid. Wiadomość e-mail zwróconą po pomyślnym uwierzytelnieniu można następnie pobrać z "OpenIDAuthenticationToken", która ostatecznie zostanie przekazana jako parametr do funkcji loadUserByUsername.

Jeśli użytkownik jest zarejestrowany w tej wiadomości e-mail, uwierzytelnianie zostało zakończone. W przeciwnym razie możesz zasugerować użytkownikowi zarejestrowanie się przez tę wiadomość e-mail lub wyświetlenie strony błędu logowania.

+0

Na rzeczywisty powód PO odpowiada Ritesh (komentarz do zaakceptowanej odpowiedzi!) – manikanta

Powiązane problemy