mkyong example enableoauth2sso oauth-2.0 spring-boot spring-security-oauth2 userdetailsservice

example - Spring Boot OAuth 2.0 UserDetails usuario no encontrado



spring boot oauth2 jdbc (2)

Enfrenté el mismo problema y pasé horas investigando el caso. Como solución alternativa, si está utilizando Spring Boot versión 1.1.8.RELEASE, descárguelo a 1.0.2.RELEASE. Las cosas salieron bien de esa manera, pero aún no investigué las razones del problema de compatibilidad con Spring Boot versión 1.1.8.RELEASE.

Soy nuevo en Spring Boot, y estoy tratando de configurar OAuth 2.0. El problema que tengo en este momento es que sigo recibiendo el siguiente mensaje cuando intento solicitar un token de acceso:

{"error": "invalid_grant", "error_description": "credenciales incorrectas"}

El mensaje de error en la consola Spring Boot indica que no se puede encontrar al usuario.

: Intento de autenticación utilizando org.springframework.security.authentication.dao.DaoAuthenticationProvider: User ''stromero'' no encontrado: devolución de instancia en caché de singleton bean ''authenticationAuditListener''

Implementé un usuario personalizado que ya se ha guardado en una base de datos usando JPA, no entiendo por qué Spring Security no puede encontrar a este usuario, puede ser un problema con mi lógica o configuración. Si alguien con más experiencia puede mirar mi código y quizás guiarme en la dirección correcta, eso sería muy apreciado.

Esta es la solicitud HTTP:

POST / oauth / token HTTP / 1.1 Host: localhost: 8181 Autorización: Basic YnJvd3NlcjpzZWNyZXQ = Cache-Control: no-cache Content-Type: application / x-www-form-urlencoded username = stromero & password = password & client_id = browser & client_secret = secret & grant_type = contraseña

Estas son las clases que utilicé para implementar mi usuario personalizado y OAuth 2.0

@Repository public interface UserRepository extends CrudRepository<CustomUser, String> { public CustomUser findByUsername(String name); }

Debajo está el usuario personalizado que he creado

@Entity @Table (name = "custom_user") public class CustomUser { @Id @Column(name = "id", nullable = false, updatable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @Column(name = "username", unique=true, nullable = false) private String username; @Column(name = "password", nullable = false) private String password; @ElementCollection private List<String> roles = new ArrayList<>(); public List<String> getRoles() { return roles; } public void setRoles(List<String> roles) { this.roles = roles; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }

A continuación se muestra un servicio personalizado que lee la información del usuario de la base de datos y la devuelve como un objeto UserDetails.

@Service @Transactional(readOnly = true) public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { CustomUser customUser = userRepository.findByUsername(s); boolean enabled = true; boolean accountNonExpired = true; boolean credentialsNonExpired = true; boolean accountNonLocked = true; return new User( customUser .getUsername(), customUser .getPassword().toLowerCase(), enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities(customUser.getRoles())); } public Collection<? extends GrantedAuthority> getAuthorities(List<String> roles) { List<GrantedAuthority> authList = getGrantedAuthorities(roles); return authList; } public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); for (String role : roles) { authorities.add(new SimpleGrantedAuthority(role)); } return authorities; } }

La siguiente clase es una estructura de datos que contiene los servicios UserDetailsService y ClientDetailsService

public class ClientAndUserDetailsService implements UserDetailsService, ClientDetailsService { private final ClientDetailsService clients; private final UserDetailsService users; private final ClientDetailsUserDetailsService clientDetailsWrapper; public ClientAndUserDetailsService(ClientDetailsService clients, UserDetailsService users) { super(); this.clients = clients; this.users = users; clientDetailsWrapper = new ClientDetailsUserDetailsService(this.clients); } @Override public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException { return clients.loadClientByClientId(clientId); } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserDetails user = null; try{ user = users.loadUserByUsername(username); }catch(UsernameNotFoundException e){ user = clientDetailsWrapper.loadUserByUsername(username); } return user; } }

La clase a continuación es mi configuración para OAuth 2.0 usando Spring Boot

@Configuration public class OAuth2SecurityConfiguration { @Configuration @EnableWebSecurity protected static class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired protected void registerAuthentication( final AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } } @Configuration @EnableResourceServer protected static class ResourceServer extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.authorizeRequests().antMatchers("/oauth/token").anonymous(); // Require all GET requests to have client "read" scope http.authorizeRequests().antMatchers(HttpMethod.GET, "/**") .access("#oauth2.hasScope(''read'')"); // Require all POST requests to have client "write" scope http.authorizeRequests().antMatchers(HttpMethod.POST,"/**") .access("#oauth2.hasScope(''write'')"); } } @Configuration @EnableAuthorizationServer @Order(Ordered.LOWEST_PRECEDENCE - 100) protected static class AuthorizationServer extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; private ClientAndUserDetailsService combinedService; public AuthorizationServer() throws Exception { ClientDetailsService clientDetailsService = new InMemoryClientDetailsServiceBuilder() .withClient("browser") .secret("secret") .authorizedGrantTypes("password") .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") .scopes("read","write") .resourceIds("message") .accessTokenValiditySeconds(7200) .and() .build(); // Create a series of hard-coded users. UserDetailsService userDetailsService = new CustomUserDetailsService(); combinedService = new ClientAndUserDetailsService(clientDetailsService, userDetailsService); } @Bean public ClientDetailsService clientDetailsService() throws Exception { return combinedService; } @Bean public UserDetailsService userDetailsService() { return combinedService; } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.withClientDetails(clientDetailsService()); } } }

A continuación está mi archivo pom.xml

<properties> <tomcat.version>8.0.8</tomcat.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- Postgres JDBC Driver --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>9.2-1002-jdbc4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- Hibernate validator --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.0.3.RELEASE</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>17.0</version> </dependency> </dependencies>


Sí, tenía el mismo problema ... quería usar UserDetailsService de JPA, pero el mismo problema: no se pudo encontrar al usuario ... finalmente lo resolvió, gracias a las muestras OAuth2 de Dave Syer en GitHub.

El problema parece ser que la instancia de authenticationManager está autocandida en la clase @EnableAuthorizationServer AuthorizationServer . AuthenticationManager está autoconectado allí y parece inicializarse con DAOAuthenticationProvider predeterminado, y por alguna razón no utiliza JPA UserDetailsService personalizado inicializando authenticationManager en WebSecurityConfiguration .

En Dave Syer, los ejemplos de authenticationManager están expuestos como un bean en WebSecurityConfiguration :

@Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }

luego, en AuthorizationServer iniciamos AutoWire authenticationManager de la siguiente manera:

@Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager;

Una vez que lo hice, finalmente logré que mi usuario se autenticara en mi repositorio de usuarios de JPA.