我是Spring Boot的新手,我试图配置OAuth 2.0。我在这个时刻遇到的问题是,我不断收到以下消息时,我试图请求访问令牌:春季启动OAuth 2.0 UserDetails用户未找到
{ “错误”:“invalid_grant”, “ERROR_DESCRIPTION”:“坏凭据“ }
Spring Boot控制台中的错误消息表示无法找到用户。
:使用org.springframework.security.authentication.dao.DaoAuthenticationProvider 验证尝试:用户“stromero”未找到 :单豆“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<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用户配置春季启动
@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>
我看不到任何东西(您确定用户在数据库中,并且您正在连接到该数据库)?尽管你的代码中有些奇怪的东西(其中没有一个会导致你的症状):1.存储库意味着主键是一个“String”,但“@ Entity”具有“Long”; 2.我不明白联合用户/客户详细信息服务; 3.您似乎尝试使匿名用户可以使用/令牌端点; 4.您在表单参数中使用客户端凭据,但您尚未告知auth服务器要执行此操作。也许你可以分享一个完整的项目? – 2014-10-07 06:03:09
感谢您的回应,我测试了资源库,并且能够检索用户,据说我将使用long作为主键。我将努力摆脱综合服务。我不知道如何处理3和4.我不能共享整个项目,但是我已经基于以下示例的很多源代码,请让我知道这是否有帮助。 https://github.com/juleswhite/mobilecloud-14/tree/master/examples/9-VideoServiceWithOauth2正如我之前所说的JPA部分似乎没有问题。我试图实现的OAuth 2.0流程是密码授予。 – 2014-10-07 12:28:41
这也可能提供更多的上下文 - > https://www.youtube.com/watch?v=KmCvyg20xi4 – 2014-10-07 13:03:11