我是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