我是Spring Boot的新手,我正在尝试配置OAuth 2.0.我现在遇到的问题是,当我尝试请求访问令牌时,我不断收到以下消息:
{"error":"invalid_grant","error_description":"凭据错误"}
Spring Boot控制台中的错误消息表明找不到用户.
:使用org.springframework.security.authentication.dao.DaoAuthenticationProvider验证尝试:用户"stromero"未找到:返回singleton的bean的缓存实例"authenticationAuditListener"
我已经使用JPA实现了已经保存到数据库的自定义用户,我无法确定为什么Spring Security无法找到此用户,这可能是我的逻辑或配置问题.如果具有更多经验的人可以查看我的代码并且可能指导我找到正确的方向,那将非常感激.
这是HTTP请求:
POST /的OAuth /令牌HTTP/1.1主机:本地主机:8181授权:基本YnJvd3NlcjpzZWNyZXQ =缓存控制:无缓存内容类型:应用程序/ x-WWW窗体-urlencoded用户名= stromero和密码=密码&CLIENT_ID =浏览器&client_secret =秘密&grant_type =密码
这些是我用来实现自定义用户和OAuth 2.0的类
@Repository public interface UserRepository extends CrudRepository{ 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 Listroles = new ArrayList<>(); public List getRoles() { return roles; } public void setRoles(List 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(Listroles) { List authList = getGrantedAuthorities(roles); return authList; } public static List getGrantedAuthorities(List roles) { List authorities = new ArrayList (); 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; } }
下面的类是我使用Spring Boot配置的OAuth 2.0
@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文件
8.0.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-logging org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-starter-test org.postgresql postgresql 9.2-1002-jdbc4 org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-security org.springframework.security.oauth spring-security-oauth2 2.0.3.RELEASE com.google.guava guava 17.0
小智.. 17
是的,我有同样的问题...想要使用JPA UserDetailsService
但是同样的问题 - 用户无法找到...最终得到了解决,感谢Dave Syer在GitHub上的OAuth2样本.
问题似乎是在@EnableAuthorizationServer AuthorizationServer
类中自动装配的authenticationManager实例中.AuthenticationManager在那里自动装配,似乎默认初始化DAOAuthenticationProvider
,并且由于某种原因它不使用自定义JPA UserDetailsService
我们用in初始化authenticationManager WebSecurityConfiguration
.
在Dave Syer示例中,authenticationManager作为bean公开WebSecurityConfiguration
:
@Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }
然后在AuthorizationServer
我们autowire authenticationManager中如下:
@Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager;
一旦我这样做了,我终于设法让我的用户通过我的客户JPA用户存储库进行身份验证.
是的,我有同样的问题...想要使用JPA UserDetailsService
但是同样的问题 - 用户无法找到...最终得到了解决,感谢Dave Syer在GitHub上的OAuth2样本.
问题似乎是在@EnableAuthorizationServer AuthorizationServer
类中自动装配的authenticationManager实例中.AuthenticationManager在那里自动装配,似乎默认初始化DAOAuthenticationProvider
,并且由于某种原因它不使用自定义JPA UserDetailsService
我们用in初始化authenticationManager WebSecurityConfiguration
.
在Dave Syer示例中,authenticationManager作为bean公开WebSecurityConfiguration
:
@Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }
然后在AuthorizationServer
我们autowire authenticationManager中如下:
@Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager;
一旦我这样做了,我终于设法让我的用户通过我的客户JPA用户存储库进行身份验证.