Spring Boot OAuth 2.0 UserDetails пользователь не найден
Я новичок в Spring Boot и пытаюсь настроить OAuth 2.0. Проблема, с которой я столкнулся в данный момент, заключается в том, что я продолжаю получать следующее сообщение, когда пытаюсь запросить токен доступа:
{"error": "invalid_grant", "error_description": "неверные учетные данные" }
Сообщение об ошибке в консоли Spring Boot говорит, что пользователь не может быть найден.
: Попытка аутентификации с использованием org.springframework.security.authentication.dao.DaoAuthenticationProvider: пользователь 'stromero' не найден: возвращение кэшированного экземпляра одноэлементного компонента 'authenticationAuditListener'
Я реализовал пользовательского пользователя, который уже был сохранен в базе данных с использованием JPA, я не могу понять, почему Spring Security не может найти этого пользователя, это может быть связано с моей логикой или конфигурацией. Если кто-то с большим опытом может взглянуть на мой код и, возможно, направить меня в правильном направлении, это будет с благодарностью.
Это HTTP-запрос:
POST / oauth / token HTTP / 1.1 Хост: localhost:8181 Авторизация: Basic YnJvd3NlcjpzZWNyZXQ= Cache-Control: no-cache Тип содержимого: application/x-www-form-urlencoded username=stromero&password= пароль &client_id= пароль &client_secret=secret&grant_type= =
Это классы, которые я использовал для реализации своего пользовательского пользователя и OAuth 2.0
@Repository
public interface UserRepository extends CrudRepository<CustomUser, String> {
public CustomUser findByUsername(String name);
}
Ниже пользовательский пользователь, которого я создал
@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;
}
}
Ниже представлен сервис customdetails, который считывает информацию о пользователе из базы данных и возвращает ее в виде объекта 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;
}
}
Класс ниже представляет собой структуру данных, которая содержит и UserDetailsService и 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;
}
}
Класс ниже - моя конфигурация для OAuth 2.0 с использованием 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());
}
}
}
Ниже мой файл 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>
3 ответа
Да, у меня была такая же проблема... хотел использовать JPA UserDetailsService
но та же самая проблема - пользователь не мог быть найден... в конечном итоге он был решен благодаря образцам OAuth2 Дэйва Сайера на GitHub.
Проблема, кажется, в экземпляре authenticationManager, автоматически подключенном в @EnableAuthorizationServer AuthorizationServer
учебный класс. AuthenticationManager там подключен автоматически и, кажется, инициализируется по умолчанию DAOAuthenticationProvider
и по какой-то причине он не использует пользовательский JPA UserDetailsService
мы инициализируем аутентификации Manager с помощью WebSecurityConfiguration
,
В примерах Dave Syer authenticationManager выставлен как бин в WebSecurityConfiguration
:
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
затем в AuthorizationServer
мы автоматически проводим аутентификацию менеджера следующим образом:
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
Как только я это сделал, мне, наконец, удалось пройти аутентификацию моего пользователя в моем пользовательском репозитории JPA.
InitializeUserDetailsBeanManagerConfigurer имеет порядок по умолчанию как
static final int DEFAULT_ORDER = Ordered.LOWEST_PRECEDENCE - 5000;
Так что Initializee DaoAuthenticationProvider перед пользовательским.
@Order(-5001)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { ... }
Я столкнулся с той же проблемой и провел часы, расследуя это дело. В качестве обходного пути, если вы используете Spring Boot версии 1.1.8.RELEASE, понизьте его до 1.0.2.RELEASE. В таком случае все шло хорошо, но я пока не исследовал причины проблем совместимости с версией Spring Boot 1.1.8.RELEASE.