2015-11-09 6 views
5

Ho cercato di far funzionare @AuthenticationPrincipal correttamente con una classe utente personalizzata. Sfortunatamente, l'utente è sempre nullo. Ecco il codice:Spring Security @AuthenticationPrincipal

controller

@RequestMapping(value = "/", method = RequestMethod.GET) 
public ModelAndView index(@AuthenticationPrincipal User user) { 
    ModelAndView mav= new ModelAndView("/web/index"); 
    mav.addObject("user", user); 
    return mav; 
} 

Security Config

@Configuration 
@EnableWebMvcSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    CustomUserDetailsService customUserDetailsService; 

    @Autowired 
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 
      auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder()); 
    } 

}

CustomUserDetailsService

@Component 
public class CustomUserDetailsService implements UserDetailsService { 

@Autowired 
UserRepository userRepository; 

@Override 
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
    // Spring Data findByXY function 
    return userRepository.findByUsername(username); 
} 

dell'impresa utilizzatrice

public class User implements UserDetails{ 
    private String username; 
    private String password; 
    private Collection<Authority> authorities; 

    // Getters and Setters 

} 

Autorità Entity

public class Authority implements GrantedAuthority{ 
    private User user; 
    private String role; 

    // Getters and Setters 

    @Override 
    public String getAuthority() { 
     return this.getRole(); 
    } 
} 

Ho provato varie soluzioni a questo ho trovato in rete, per esempio convertendo il mio oggetto utente personalizzato come questo:

return new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), true, true, true, true, authorities); 

Gli altri modi per ottenere gli utenti attivi stanno lavorando senza un problema, ma ho trovato il @AuthenticationProvider CustomUserObject di essere il modo più pulito, che è il motivo per cui vorrei ottenere questo per funzionare. Qualsiasi aiuto è molto apprezzato.

+0

Beh .. si può sempre ottenere 'oggetto Principal', ottenere il nome del preside e trovare l'utente per nome utente. Se primavera sec. l'autenticazione viene implementata correttamente, naturalmente. –

+0

Sì, questo è quello che sto facendo al momento ... Autenticazione auth = SecurityContextHolder.getContext(). GetAuthentication(); \t \t User principal = uRep.findByUsername (auth.getName()); .. ma come ho detto, mi piacerebbe avere quella soluzione pulita quando è disponibile – Lukehey

+0

Sto affrontando esattamente lo stesso problema come te. @ AuthenticationPrincipal mi dà sempre un utente predefinito (la classe User è appena inizializzata con il costruttore predefinito), mentre ContextSecurityHolder e HttpServletRequest # getUserPrincipal() mi danno l'utente previsto (autenticato). A proposito, non dovresti annotare il tuo SecurityConfig con @ EnableWebSecurity invece di @ EnableWebMvcSecurity (deprecato in Spring Security 4+)? –

risposta

3

Invece di utilizzare @AuthenticationPrincipal è possibile specificare direttamente la propria dipendenza per l'utente autenticato nell'argomento del metodo. qualcosa come indicato sotto

@RequestMapping(value = "/", method = RequestMethod.GET) 
public ModelAndView index(Principal user) { 
    ModelAndView mav= new ModelAndView("/web/index"); 
    mav.addObject("user", user); 
    return mav; 
} 

Questo oggetto principale sarà oggetto effettivo che è stato autenticato tramite la sicurezza di primavera. Spring ti inietterà questo per te quando il metodo verrà richiamato.

+1

Come ho già detto, quei metodi funzionano tutti bene. Ma secondo la documentazione, dovrei essere in grado di ottenere il mio oggetto utente personalizzato tramite l'annotazione AuthenticationPrincipal fino a quando il mio oggetto utente implementa UserDetails e abilito WebMvcSecurity (sto usando Spring Security 4.0.2). Qualche idea di cosa potrei mancare? – Lukehey

+0

Sorprendentemente, l'approccio con '@AuthenticationPrincipal User' non ha funzionato per me, ma l'uso di' Principal' direclty ha funzionato. In attesa di una risposta da [biglietto Spring 3145] (https://jira.spring.io/browse/SEC-3145) su questo punto ... –

+0

@ RémiDoolaeghe - questa è una risposta tardiva, ma è necessario ottenere un istanza di 'UserDetails' invece di solo' User'. – Ickster

0

Ho trovato un'altra soluzione, anche questa non è quella canonica.

Nel vostro controller

@RequestMapping(value = "/login", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) 
@ResponseBody 
public ResponseEntity<UserDTO> login(@RequestBody UserDTO user){ 
    try { 
     usersService.authenticate(user.getUsername(), user.getPassword()); 
     return new ResponseEntity<UserDTO>(user, HttpStatus.OK); 
    } 
    catch (BadCredentialsException e){ 
     return new ResponseEntity<UserDTO>(HttpStatus.UNAUTHORIZED); 
    } 
} 

Dove il sistema operativo UserDTO solo una forma per contiene un nome utente e una password

Nella tua CustomUserDetailsService

public void authenticate(String username, String password){ 
    try{ 
     User user = new User(username, password); 
     Authentication request = new UsernamePasswordAuthenticationToken(user, password, Arrays.asList(WebSecurityConfiguration.USER)); 
     Authentication result = authenticationManager.authenticate(request); 
     SecurityContextHolder.getContext().setAuthentication(result);  
    } catch (InternalAuthenticationServiceException e){ 
     // treat as a bad credential 
    } 
} 

implementare il proprio AuthenticationManager

@Component 
class DefaultAuthenticationManager implements AuthenticationManager { 

@Autowired 
private CustomUserDetailsService usersService; 

public Authentication authenticate(Authentication auth) throws AuthenticationException { 
    UserDetails user = usersService.loadUserByUsername(((User)auth.getPrincipal()).getUsername()); 
    if (user != null) { 
     return new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()); 
    } 
// Handle bad credentials here 
} 
} 

ciò che è fondamentale è che il Principal nel CustomUserDetailsService#authenticate è un oggetto, non il nome del vostro utente autenticato, in modo che il quadro in grado di gestire e poi iniettare attraverso @AuthenticationPrincipal meccanismo. Questo ha funzionato per me.

0
@RequestMapping(method= RequestMethod.GET,value="/authenticate", produces = MediaType.APPLICATION_JSON_VALUE) 
public Object authenticate(@AuthenticationPrincipal Object obj) { 
    return obj; 
} 

Ho lo stesso problema, sono stato in grado di farlo funzionare. Si potrebbe usarlo con un mapper

@RequestMapping(method = RequestMethod.GET, value = "/authenticate2", produces = MediaType.APPLICATION_JSON_VALUE) 
public User authenticate2(@AuthenticationPrincipal Object obj) throws IOException { 
    return mapper.readValue(mapper.writeValueAsString(obj), User.class); 
} 

Questi hanno lavorato per me, spero che avrebbe funzionato per chiunque in futuro

0

sto affrontando lo stesso problema come te. per qualche ragione, @EnableWebSecurity di sicurezza a molla non aggiunge argumentResolver automaticamente, è necessario aggiungerlo manualmente:

<mvc:annotation-driven> 
    <mvc:argument-resolvers> 
     <bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver"/> 
    </mvc:argument-resolvers> 
</mvc:annotation-driven> 
0

Nel mio caso, ho un String indietro (il nome utente) e non l'oggetto UserDetails, cioè si dovrebbe definire la firma del metodo come

public ModelAndView index(@AuthenticationPrincipal String username) 

Questo non è strano, dal momento che @AuthenticationPrincipal in effetti restituisce Authentication.getPrincipal() e secondo la documentazione:

Nel caso di una richiesta di autenticazione con nome utente e password, questo sarebbe il nome utente. I chiamanti devono compilare il principal per una richiesta di autenticazione.

L'implementazione AuthenticationManager restituisce spesso un'autenticazione contenente informazioni più dettagliate come principale per l'uso dall'applicazione. Molti dei provider di autenticazione creeranno un oggetto UserDetails come principale. See: https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/api/

Quindi, io parto dal presupposto che l'implementazione AuthenticationManager sta tornando solo un nome utente