我正在尝试访问我的控制台 H2 localhost:8080/h2-console,但它不起作用。
我正在使用 Spring Boot (V 3.0.2)
当我尝试访问第二个 h2 数据源或尝试访问控制台路径时,问题就出现了,因为它无法决定要使用什么 H2CONSOLE.PROPERTIES。
我的安全配置是:
包 com.queueup.security;
import com.queueup.security.filters.JwtAuthenticationFilter;
import com.queueup.security.filters.JwtAuthorizationFilter;
import com.queueup.security.jwt.JwtUtils;
import com.queueup.security.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import static org.springframework.boot.autoconfigure.security.servlet.PathRequest.toH2Console;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
JwtUtils jwtUtils;
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
JwtAuthorizationFilter authorizationFilter;
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, AuthenticationManager authenticationManager) throws Exception {
JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(jwtUtils);
jwtAuthenticationFilter.setAuthenticationManager(authenticationManager);
jwtAuthenticationFilter.setFilterProcessesUrl("/login");
return httpSecurity
.csrf(AbstractHttpConfigurer::disable)
.headers().frameOptions().sameOrigin()
.and()
.authorizeHttpRequests(auth -> {
auth.requestMatchers(toH2Console()).permitAll();
auth.requestMatchers("/hello").permitAll();
auth.requestMatchers("/createUser").permitAll();
auth.requestMatchers("/h2-console/**").permitAll();
auth.requestMatchers("/api/path/**").hasAnyRole("ADMIN", "USER");
auth.requestMatchers("/api/path1/**").hasRole("USER");
auth.anyRequest().authenticated();
})
.sessionManagement(session -> {
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
})
.addFilter(jwtAuthenticationFilter)
.addFilterBefore(authorizationFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
// @Bean
// UserDetailsService userDetailsService(){
// InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
// manager.createUser(User.withUsername("santiago")
// .password("1234")
// .roles()
// .build());
//
// return manager;
// }
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
AuthenticationManager authenticationManager(HttpSecurity httpSecurity, PasswordEncoder passwordEncoder) throws Exception {
return httpSecurity.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder)
.and().build();
}
}`
我的数据源配置是:
package com.queueup;
import com.queueup.config.DataSourcesConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.HashMap;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = "com.queueup.repositories.enqueuers",
entityManagerFactoryRef = "enqueueUpEntityManager",
transactionManagerRef = "enqueueupTransactionManager")
public class PersistenceEnqueueupConfiguration {
private static final String URL = "jdbc:h2:mem:enqueueupdb;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS ENQUEUEUP";
public PersistenceEnqueueupConfiguration(){
super();
}
@Bean
public DataSource enqueueUpDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DataSourcesConfig.H2DRIVER);
dataSource.setUrl(URL);
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean enqueueUpEntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(enqueueUpDataSource());
em.setPackagesToScan(
"com.queueup.entities");
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
"create-drop");
properties.put("hibernate.dialect",
DataSourcesConfig.H2DIALECT);
properties.put("dataSourceClassName",
DataSourcesConfig.H2DRIVER);
properties.put("h2.console.enabled",
false);
properties.put("hibernate.cache.use_second_level_cache", false);
properties.put("hibernate.cache.use_query_cache", false);
em.setJpaPropertyMap(properties);
return em;
}
@Bean
public PlatformTransactionManager enqueueupTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
enqueueUpEntityManager().getObject());
return transactionManager;
}
}
和
package com.queueup;
import com.queueup.config.DataSourcesConfig;
import org.springframework.boot.autoconfigure.h2.H2ConsoleProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.HashMap;
import static org.springframework.boot.autoconfigure.security.servlet.PathRequest.toH2Console;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = "com.queueup.repositories.security",
entityManagerFactoryRef = "userEntityManager",
transactionManagerRef = "userTransactionManager")
public class PersistenceUsersConfiguration {
private static final String URL = "jdbc:h2:mem:userdb;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS USERS";
public PersistenceUsersConfiguration(){
super();
}
@Primary
@Bean
public DataSource userDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DataSourcesConfig.H2DRIVER);
dataSource.setUrl(URL);
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean userEntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(userDataSource());
em.setPackagesToScan(
"com.queueup.security.models");
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
"create-drop");
properties.put("hibernate.dialect",
DataSourcesConfig.H2DIALECT);
properties.put("dataSourceClassName",
DataSourcesConfig.H2DRIVER);
properties.put("h2.console.enabled",
true);
properties.put("h2.console.path", toH2Console());
properties.put("hibernate.cache.use_second_level_cache", false);
properties.put("hibernate.cache.use_query_cache", false);
em.setJpaPropertyMap(properties);
return em;
}
@Bean
@Primary
public PlatformTransactionManager userTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
userEntityManager().getObject());
return transactionManager;
}
}
如果我尝试访问控制台,我会得到 403 禁止,当我尝试执行第二个数据源(以任何顺序)时,我会得到
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.h2.H2ConsoleProperties'
但是我如果删除
auth.requestMatchers(toH2Console()).permitAll();
这条线可以工作,但我可以访问控制台。问题是因为 spring 不知道使用什么实例。
我定义了一个bean来尝试解决它,但是,如果我没有收到错误,我可以访问控制台。
import org.springframework.boot.autoconfigure.h2.H2ConsoleProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class H2ConsolePropConfig {
private final H2ConsoleProperties h2ConsoleProperties;
public H2ConsolePropConfig(){
h2ConsoleProperties = new H2ConsoleProperties();
h2ConsoleProperties.setEnabled(true);
h2ConsoleProperties.setPath("/h2-console");
h2ConsoleProperties.getSettings().setWebAdminPassword("");
h2ConsoleProperties.getSettings().setWebAllowOthers(true);
h2ConsoleProperties.getSettings().setTrace(true);
}
@Bean
@Primary
public H2ConsoleProperties getH2ConsoleProperties() {
return h2ConsoleProperties;
}
}
也许如果我知道如何将它注入到我的主要数据源中,我就可以让它继续运行。
如果您能帮助我,我将不胜感激。
提前致谢。 问候
让我们看看问题是什么:
我们如何解决它:
我们需要动态更改默认数据库
假设您有 2 个内存数据库,其中一个用于学生,一个用于会员
步骤:
public enum AuthServerDatabase {
CLIENT_DB_STUDENT, CLIENT_DB_MEMBER
}
public class AuthServerDatabaseContextHolder {
private static ThreadLocal<AuthServerDatabase> CONTEXT = new ThreadLocal<>();
public static void set(AuthServerDatabase clientDatabase) {
Assert.notNull(clientDatabase, "clientDatabase cannot be null");
CONTEXT.set(clientDatabase);
}
public static AuthServerDatabase getClientDatabase() {
return CONTEXT.get();
}
public static void clear() {
CONTEXT.remove();
}
}
public class AuthServerSourceRouter extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return AuthServerDatabaseContextHolder.getClientDatabase();
}
}
@Configuration
public class DBConfig {
public DataSource studentDataSource()
{
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url(" your db connection ur");
dataSourceBuilder.username("your db username");
dataSourceBuilder.password("your db password");
return dataSourceBuilder.build();
}
public DataSource membersDataSource()
{
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url(" your db connection ur");
dataSourceBuilder.username("your db username");
dataSourceBuilder.password("your db password");
return dataSourceBuilder.build();
}
@Bean
public DataSource clientDatasource()
{
Map<Object, Object> targetDataSources = new HashMap<>();
DataSource studentDB = studentDataSource();
DataSource membersDB = membersDataSource();
targetDataSources.put(AuthServerDatabase.CLIENT_DB_STUDENT, studentDB);
targetDataSources.put(AuthServerDatabase.CLIENT_DB_MEMBER, membersDB);
AuthServerSourceRouter clientRoutingDatasource = new AuthServerSourceRouter();
clientRoutingDatasource.setTargetDataSources(targetDataSources);
clientRoutingDatasource.setDefaultTargetDataSource(studentDB);
return clientRoutingDatasource;
}
}
AuthServerDatabaseContextHolder.set(AuthServerDatabase.CLIENT_DB_MEMBER);
//与会员数据库关联的查询或业务逻辑
AuthServerDatabaseContextHolder.clear();
首先,感谢您抽出时间。
我在你的 dbconfig 中做了一些修改来保存我的 befores beans 和我的 DBCONFIG 类
@Configuration
@AllArgsConstructor
public class DBConfig {
private final PersistenceUsersConfiguration persistenceUsersConfiguration;
private final PersistenceEnqueueupConfiguration persistenceEnqueueupConfiguration;
@Bean
public DataSource clientDataSource(){
Map<Object, Object> targetDataSources = new HashMap<>();
DataSource userDB = persistenceUsersConfiguration.userDataSource();
DataSource enqueueUpDB = persistenceEnqueueupConfiguration.enqueueUpDataSource();
targetDataSources.put(AuthServerDataBase.CLIENT_DB_USERS, userDB);
targetDataSources.put(AuthServerDataBase.CLIENT_DB_ENQUEUEUP, enqueueUpDB);
AuthServerSourceRouter clientRoutingDatasource = new AuthServerSourceRouter();
clientRoutingDatasource.setTargetDataSources(targetDataSources);
clientRoutingDatasource.setDefaultTargetDataSource(userDB);
return clientRoutingDatasource;
}
和我的前配置数据源bean,我退出了@Configuration并使用了@Components。使用 debug 初始化应用程序,数据源是正确的,但是当我尝试访问 localhost:8080/h2 时,我得到了相同的 500 错误。
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.h2.H2ConsoleProperties' available