2015-10-12 8 views
9

La scorsa settimana ho iniziato ad estendere la classe UserDetails per poter supportare un campo personalizzato. La particolarità di questo campo è che viene riempito con un valore che dipende da un parametro di richiesta. Sono riuscito a implementarlo correttamente (quindi la domanda non si concentra su questo).Spring Security Ouath2: Extended UserDetails non restituito dall'oggetto Principal

Ora il problema è che dopo un login di successo l'oggetto UserDetails viene riempito correttamente (sono stato in grado di vederlo usando un AuthenticationSuccessHandler) e il client riceve un token JWT dal provider OAuth2. Il client tenta quindi di recuperare più dettagli sull'utente visitando l'endpoint "/ uaa/user". Questo è impostato per restituire l'oggetto principale. Ma dopo aver controllato il contenuto dell'oggetto principale, sono stato suppreso che l'oggetto UserDetails fosse mancante. Il metodo getPrincipal() ha restituito solo il nome utente anziché l'oggetto UserDetails.

Secondo this question questo è il risultato di un accesso non riuscito. L'AuthenticationToken (in questo caso un UsernamePasswordAuthenticationToken) viene rifiutato da AuthenticationManager. Non ho idea del perché dovrebbe fare una cosa del genere. L'autenticazione con l'oggetto UserDetails predefinito sembra funzionare correttamente. Qualcuno può aiutarmi a risolvere questo problema?

Alcuni dettagli sulle classi implementate (come menzionato sopra). Alcuni codici sono stati lasciati qui per motivi.

CustomUserDetails

public class CustomUserDetails extends User { 

    private final Integer custom; 

    public CustomUserDetails (...default params..., Integer custom) { 
    super(...default params...); 
    this.custom = custom; 
    } 
} 

CustomUserDetailsService

@Service 
public class CustomUserDetailsService implements UserDetailsService { 
    @Override 
    public CustomUserDetails loadUserByUsername(String username) throw UsernameNotFoundException { 
    return new CustomUserDetails(...default params..., 12345); 
    } 
} 

configurazione

@Autowired 
private CustomUserDetails userDetails; 

@Override 
protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
    auth.userDetailsService(userDetails); 
} 

utente Endpoint

@RequestMapping(value = "/user", method = RequestMethod.GET) 
@ResponseBody 
public Principal getDetails(Principal user) { 
    return user; 
} 

l'oggetto principale tornato qui dovrebbe avere le UserDetails oggetto all'interno di esso e dovrebbe restituire questo al client. Ma invece di quello restituisce solo una stringa con lo username quando chiamate getPrincipal();

Alla fine voglio il JSON restituito dall'endpoint Utente (che restituisce l'oggetto Principio) per contenere il campo personalizzato che ho aggiunto a UserDetails.

Grazie in anticipo.

+0

si può mostrare più particolari o meglio un link al tuo progetto come GitHub? Quindi possiamo facilmente individuare il problema tracciando il codice. – vine

+0

Hai provato '@AuthenticationPrincipal CustomUserDetails details' come argomento del metodo' getDetails'? –

+2

Mi sono completamente dimenticato di questa domanda. Abbiamo finito per utilizzare un approccio diverso per ottenere i dettagli dell'utente (chiamando invece un endpoint microservice utente). Ma per rispondere a questa domanda cercherò di trovare una soluzione che non implichi un'applicazione separata. –

risposta

4

In generale, è necessario l'annotazione @AuthenticationPrincipal, ma io suggerisco di costruire la propria annotazione, qualcosa di simile:

/** 
* Our own {@link AuthenticationPrincipal} annotation as suggested by 
* http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#mvc-authentication-principal 
* 
*/ 
@Target({ElementType.PARAMETER, ElementType.TYPE}) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@AuthenticationPrincipal 
public @interface CurrentUser {} 

Poi si può avere questo Principal in questo modo:

@RequestMapping(..) 
public Principal test(@CurrentUser Principal principal){..} 

MA, IMHO dovresti avere il tuo Impl of Principal, o piuttosto estendere l'impl esistente. qualcosa di simile:

public MyPrincipal extends org.springframework.security.core.userdetails.User {..} 

In questo caso è possibile restituire valori qualunque si desideri.

+0

Questo sembra un buona soluzione per me. Appena testato, questo è esattamente il risultato di cui avevo bisogno (prima di spostare l'endpoint su un'altra applicazione). @ gt_ebuddy Questa soluzione funziona anche per te? –

+0

In realtà, stavo usando mongodb e in seguito ho scoperto che richiede l'implementazione di 'Converter' come: https://gist.github.com/gtiwari333/86cd25ef352d5a57c9567b5f62ae2388#file-oauth2authenticationreadconverter-java-L51 così posso creare l'oggetto principale personalizzato lì . – gtiwari333

0

È possibile utilizzare questo metodo, in ogni caso per ottenere dettagli dettagliati degli utenti, nel controller o ovunque sia necessario. Ci possono essere contro in questo metodo, ma è efficace.

Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
MyUserDetails myUser = (MyUserDetails) auth.getPrincipal(); 

public class MyUserDetails implements 
org.springframework.security.core.userdetails.UserDetails { 

private User user; //This is the user domain. 
private String firstName; 
private String lastName; 

public Collection<? extends GrantedAuthority> getAuthorities() { 
    List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(); 
    authList.add(new SimpleGrantedAuthority(user.getRole().getName())); 
    return authList; 
} 


public String getPassword() { 
    return user.getPassword(); 
} 

public String getUsername() { 
    return user.getEmail(); 
} 

public boolean isAccountNonExpired() { 
    return ((user.getAccountState() == AccountState.InActive) || (user.getAccountState() == AccountState.Blocked) ? false : true); 
} 

public boolean isAccountNonLocked() { 
    return (user.getAccountState() == AccountState.Locked) ? false : true; 
} 

public boolean isCredentialsNonExpired() { 
    return true; 
} 

public boolean isEnabled() { 
    return ((user.getAccountState() == AccountState.Active) 
      || (user.getAccountState() == AccountState.PasswordReset) 
      || (user.getAccountState() == AccountState.UnVerified) ? true 
      : false); 
} 

public User getUser() { 
    return user; 
} 

public void setUser(User user) { 
    this.user = user; 
} 


public String getFirstName() { 
    return firstName; 
} 

public void setFirstName(String firstName) { 
    this.firstName = firstName; 
} 

public String getLastName() { 
    return lastName; 
} 


public void setLastName(String lastName) { 
    this.lastName = lastName; 
} 


} 
Problemi correlati