J'ai un projet utilisant spring boot, spring security avec oauth2. Quand j'utilise SecurityContextHolder.getContext (). GetAuthentication (). GetPrincipal ()
cette méthode ne retourne que le nom d'utilisateur à la fin des exemples que je vois cette méthode retourne l'implentation UserDetails.
Suivez les paramètres
OAuthSecurityConfig.java:
package br.com.altha.api.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler; import org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler; import br.com.altha.api.handler.RestExceptionHandler; @Configuration @Import(Encoders.class) public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Bean public RestExceptionHandler handlerError() { return new RestExceptionHandler(); } @Bean public MethodSecurityExpressionHandler createExpressionHandler() { return new OAuth2MethodSecurityExpressionHandler(); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/public/**").permitAll() .antMatchers("/private/**").authenticated() .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler()); } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.stateless(true); } }
AuthorizationServerConfig.java:
package br.com.altha.api.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; import br.com.altha.api.security.CustomUserDetailsService; @Configuration public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { private static final String SECRET = "PASSWORD"; @Autowired private AuthenticationManager authenticationManager; @Autowired private PasswordEncoder oauthClientPasswordEncoder; @Autowired private CustomUserDetailsService userDetailsService; @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) { oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()").passwordEncoder(oauthClientPasswordEncoder); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("altha-adms") .secret(oauthClientPasswordEncoder.encode(SECRET)) .scopes("write", "read") .authorizedGrantTypes("password", "refresh_token") .accessTokenValiditySeconds(60/*1800*/) .refreshTokenValiditySeconds(1800); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore()) .accessTokenConverter(accessTokenConverter()) .authenticationManager(authenticationManager) .reuseRefreshTokens(false) .userDetailsService(userDetailsService); } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(SECRET); return converter; } @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter()); } }
ResourceServerConfig.java:
package br.com.altha.api.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.annotation.Order; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import br.com.altha.api.security.CustomUserDetailsService; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled=true) @EnableAuthorizationServer @EnableResourceServer @Order(SecurityProperties.BASIC_AUTH_ORDER-2) @Import(Encoders.class) public class OAuthSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private PasswordEncoder userPasswordEncoder; @Autowired private CustomUserDetailsService userDetailsService; @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(userPasswordEncoder); } }
4 Réponses :
Avec Spring Boot 1.5.x, vous pouvez implémenter un PrincipalExtractor
et remplacer son Object extractPrincipal (Map
. L'exemple de composant suivant a un UserdetailsService autowired pour rechercher l'objet UserDetails basé sur le nom d'utilisateur.
@Component public class MyPrincipalExtractor implements PrincipalExtractor { private UserDetailsService userDetailsService; @Value("${security.oauth2.client.principal-attribute}") private String principalAttribute; @Autowired public MyPrincipalExtractor(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } @Override public Object extractPrincipal(Map<String, Object> map) { if (!map.containsKey(principalAttribute)) { return null; } final String username = (String) map.get(principalAttribute); try { return userDetailsService.loadUserByUsername(username); } catch (UsernameNotFoundException e) { // This may be the first time this user is accessing the system, // maybe you want to extract some other attributes from the map // and return a different type of user object that can be used to // create a new user. } } }
Maintenant, le SecurityContextHolder.getContext (). GetAuthentication (). GetPrincipal () code> contiendra un objet UserDetails.
Pour un didacticiel plus détaillé, voir:
Cela fait référence à Spring OAuth2 (et plus spécifiquement au support Spring Boot). Ce projet est en mode maintenance car à partir de Spring Security 5 OAuth2 est pris en charge par défaut pour Spring Security. Il n'y a aucune garantie que cela fonctionnera avec le plus récent Spring Security ni Spring Boot 2.0. C'est aussi pour Spring Boot 1.5 et non Spring Security 1.5.
@ M.Deinum oui je voulais dire Spring Boot 1.5.x. Mettra à jour la réponse. Et oui, cela peut ne pas fonctionner avec le nouveau Spring Security 5.
Cette méthode ne fonctionne pas avec moi, probablement parce que j'utilise Spring Boot 2x
C'est correct @PauloCarvalho cette méthode ne fonctionne que pour Spring Boot 1.5.x et Spring Security 4.2.x
J'ai pu résoudre ce problème avec ce code:
J'ai ajouté un bean à UserAuthenticationConverter
@Bean public JwtAccessTokenConverter accessTokenConverter() { final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter(); jwtAccessTokenConverter.setSigningKey(SECRET); ((DefaultAccessTokenConverter) jwtAccessTokenConverter.getAccessTokenConverter()) .setUserTokenConverter(userAuthenticationConverter()); return jwtAccessTokenConverter; }
Après cela, j'ai défini ce bean dans le JwtAccessTokenConverter p>
@Bean public UserAuthenticationConverter userAuthenticationConverter() { DefaultUserAuthenticationConverter defaultUserAuthenticationConverter = new DefaultUserAuthenticationConverter(); defaultUserAuthenticationConverter.setUserDetailsService(userDetailsService); return defaultUserAuthenticationConverter; }
C'est génial, j'en aurai besoin lorsque nous passerons à Spring Boot 2
merci, cela fonctionne dans mon serveur de ressources pour obtenir l'objet UserDetails personnalisé via: authentification finale authentification = SecurityContextHolder.getContext (). getAuthentication (); if (authentication! = null && authentication instanceof OAuth2Authentication) {final Object principal = ((OAuth2Authentication) authentication) .getUserAuthentication () .getPrincipal ();
Cela fonctionne pour moi. Merci.
@Bean public UserAuthenticationConverter userAuthenticationConverter() { DefaultUserAuthenticationConverter defaultUserAuthenticationConverter = new DefaultUserAuthenticationConverter(); defaultUserAuthenticationConverter.setUserDetailsService(userDetailsService); return defaultUserAuthenticationConverter; } @Bean public JwtAccessTokenConverter accessTokenConverter() { final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter(); jwtAccessTokenConverter.setSigningKey(SECRET); ((DefaultAccessTokenConverter) jwtAccessTokenConverter.getAccessTokenConverter()) .setUserTokenConverter(userAuthenticationConverter()); return jwtAccessTokenConverter; }
La cause varierait en fonction de la technique d'authentification / d'autorisation, mais dans mon cas, j'ai 2 filtres d'authentification / autorisation, le problème était de passer le username
au lieu de l'ensemble de l'objet utilisateur au UsernamePasswordAuthenticationToken < / code> dans le filtre d'autorisation:
renvoie un nouveau UsernamePasswordAuthenticationToken (userDetails.getUsername (), .....);
Le premier argument du constructeur est défini sur l'objet Principe
.
La solution était donc de transmettre tout l'objet userDetails
renvoie un nouveau UsernamePasswordAuthenticationToken (userDetails, .....);
getPrincipal
peut renvoyer ce qu'il veut. Donc, ce qui est retourné dépend de l'implémentation de l 'Authentification
utilisée et l'OAuth2Authentication
renvoie uneString
. Donc, à moins que vous ne réimplémentiez toute la partie oauth2, c'est ce avec quoi vous devez vivre. Donc, en bref, cela fonctionne comme il se doit / a été conçu pour fonctionner.Alors, qu'est-ce que je fais pour implémenter toute la partie oauth2? Pouvez-vous me montrer un exemple?