[英]spring boot oauth2 with jdbc token store gives oauth_access_token relation doesn't exist
我正在嘗試將spring boot與OAuth2集成。 通過以下https://github.com/royclarkson/spring-rest-service-oauth,我能夠使用InMemoryStore來處理令牌。 但是當我嘗試使用JdbcTokenStore和postgres數據庫實現它時,我得到了錯誤
Handling error: BadSqlGrammarException, PreparedStatementCallback; bad SQL grammar [select token_id, token from oauth_access_token where authentication_id = ?]; nested exception is org.postgresql.util.PSQLException: ERROR: relation "oauth_access_token" does not exist
我檢查了我的數據庫,表存在。
網絡安全配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static PasswordEncoder encoder;
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
if(encoder == null) {
encoder = new BCryptPasswordEncoder();
}
return encoder;
}
}
Oauth2Config
@Configuration
public class OAuth2ServerConfiguration {
private static final String RESOURCE_ID = "restservice";
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
// @formatter:off
resources
.tokenStore(tokenStore)
.resourceId(RESOURCE_ID);
// @formatter:on
}
@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/users").hasRole("ADMIN")
.antMatchers("/userAccounts/create").permitAll()
.antMatchers("/greeting").authenticated();
// @formatter:on
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
@Autowired
DataSource dataSource;
@Bean
public JdbcTokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
private static PasswordEncoder encoder;
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
// @formatter:off
endpoints
//.tokenStore(new InMemoryTokenStore())
.tokenStore(tokenStore())
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
// @formatter:on
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// @formatter:off
clients
//.inMemory()
.jdbc(dataSource)
.passwordEncoder(passwordEncoder());
//.withClient("clientapp")
//.authorizedGrantTypes("password", "refresh_token")
//.authorities("USER")
//.scopes("read", "write")
//.resourceIds(RESOURCE_ID)
//.secret("123456");
// @formatter:on
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(tokenStore());
//tokenServices.setTokenStore(new InMemoryTokenStore());
return tokenServices;
}
@Bean
public PasswordEncoder passwordEncoder() {
if(encoder == null) {
encoder = new BCryptPasswordEncoder();
}
return encoder;
}
}
}
CustomUserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
private AccountInfoRepository accountInfoRepository;
@Autowired
public CustomUserDetailsService(AccountInfoRepository accountInfoRepository) {
this.accountInfoRepository = accountInfoRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
AccountInfo user = accountInfoRepository.findByUsername(username);
System.out.println("USER IS "+user);
if (user == null) {
throw new UsernameNotFoundException(String.format("User %s does not exist!", username));
}
return new UserRepositoryUserDetails(user);
}
private final static class UserRepositoryUserDetails extends AccountInfo implements UserDetails,Serializable {
private static final long serialVersionUID = 1L;
private UserRepositoryUserDetails(AccountInfo user) {
super(user);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return getRoles();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
}
application.properties
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.default_schema=test
spring.jpa.hibernate.ddl-auto=none
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/test
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.schema=test
spring.profiles.active=dev
#Application specific
security.oauth2.client.client-id=clientapp
security.oauth2.client.client-secret=123456
security.oauth2.client.authorized-grant-types=password,refresh_token
security.oauth2.client.authorities=ROLE_USER
security.oauth2.client.scope=read,write
security.oauth2.client.resource-ids=restservice
security.oauth2.client.access-token-validity-seconds=1800
用戶對象
@JsonIgnoreProperties(ignoreUnknown = true)
@Entity
@Table(name = "account_info")
public class AccountInfo implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "account_id")
Integer accountId;
@Column(name = "account_name")
String accountName;
@Column(name = "address_line_1")
String addressLine1;
@Column(name = "address_line_2")
String addressLine2;
String city;
String state;
String country;
@NotEmpty
@Column(unique = true, nullable = false)
String username;
@NotEmpty
String password;
String email;
@JsonIgnore
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "role_id") })
private Set<Role> roles = new HashSet<>();
public AccountInfo() {
}
public AccountInfo(AccountInfo accountInfo) {
this.accountId = accountInfo.getAccountId();
this.accountName = accountInfo.getAccountName();
this.username = accountInfo.getUsername();
this.password = accountInfo.getPassword();
this.roles = accountInfo.getRoles();
}
public boolean isSetup() {
return isSetup;
}
public void setSetup(boolean isSetup) {
this.isSetup = isSetup;
}
public Integer getAccountId() {
return accountId;
}
public void setAccountId(Integer accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public String getAddressLine1() {
return addressLine1;
}
public void setAddressLine1(String addressLine1) {
this.addressLine1 = addressLine1;
}
public String getAddressLine2() {
return addressLine2;
}
public void setAddressLine2(String addressLine2) {
this.addressLine2 = addressLine2;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
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;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
這就是我創建用戶的方式
account.setPassword(new BCryptPasswordEncoder().encode(account.getPassword()));
Set<Role> roles = new HashSet<>();
roles.add(new Role("ROLE_USER",1));
account.setRoles(roles);
AccountInfo savedAccount=accountInfoRepository.save(account);
OAuth2表
CREATE TABLE oauth_client_details (
client_id VARCHAR(256) PRIMARY KEY,
resource_ids VARCHAR(256),
client_secret VARCHAR(256),
scope VARCHAR(256),
authorized_grant_types VARCHAR(256),
web_server_redirect_uri VARCHAR(256),
authorities VARCHAR(256),
access_token_validity INTEGER,
refresh_token_validity INTEGER,
additional_information VARCHAR(4096),
autoapprove VARCHAR(256)
);
ALTER TABLE oauth_client_details OWNER TO postgres;
CREATE TABLE oauth_client_token (
token_id VARCHAR(256),
token bytea,
authentication_id VARCHAR(256),
user_name VARCHAR(256),
client_id VARCHAR(256)
);
ALTER TABLE oauth_client_token OWNER TO postgres;
CREATE TABLE oauth_access_token (
token_id VARCHAR(256),
token bytea,
authentication_id VARCHAR(256),
user_name VARCHAR(256),
client_id VARCHAR(256),
authentication bytea,
refresh_token VARCHAR(256)
);
ALTER TABLE oauth_access_token OWNER TO postgres;
CREATE TABLE oauth_refresh_token (
token_id VARCHAR(256),
token bytea,
authentication bytea
);
ALTER TABLE oauth_refresh_token OWNER TO postgres;
CREATE TABLE oauth_code (
code VARCHAR(256), authentication bytea
);
ALTER TABLE oauth_code OWNER TO postgres;
OAuth2 JDBC連接器不了解架構。 您需要將默認架構添加到數據庫中的用戶配置文件中,或者在URL中明確指定它。 像這樣: jdbc:postgresql://localhost:5432/test?currentSchema=test
。
通過刪除oauth_access_token表中的所有內容並在資源服務器和身份驗證服務器上添加設置tokenStore來解決此問題,如下所示:
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
}
得到它的工作
ALTER USER postgres SET search_path TO test,public;
不推薦使用USER
地方,相反
ALTER ROLE postgres SET search_path TO test,public;
該值可以通過以下方式驗證:
SHOW search_path;
這將包括dataSource搜索路徑中的架構。 所以jdbc查詢現在會遇到表。
或者或更恰當地,雙重檢查test?currentSchema=test
以確保db和模式如上所述。 當使用docker時 ,它會根據POSTGRES_USER
設置基於POSTGRES_USER
的數據庫,除非使用POSTGRES_DB
指定,因此我的root
(你的case postgres
)用戶沒有看到test
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.