修复了尝试使用基于会话的身份验证在休眠 Spring 引导中实现多租户服务时出现的注销错误"未选择数据库"



我正在使用Hibernate Spring启动在我的项目中集成多租户逻辑,我能够使用DNS方法在数据库之间交换, 例如: db_name.示例.com -> 数据库名称 = db_name 我在项目中使用基于会话的身份验证。

问题是当我想注销会话时,项目返回以下错误:

[从用户名 = ?] 的persistent_logins中删除;SQL 状态 [3D000];错误代码 [1046];未选择数据库;嵌套异常是 java.sql.SQLException:未选择数据库

我发现这篇文章与我的情况相似, 如何使用 spring-security-saml 在多租户 SAML 应用程序中使用全局注销? 我已经尝试过,但无济于事。

我正在使用以下来自以下网站的多租户代码示例 https://javadeveloperzone.com/hibernate/spring-hibernate-xml-multi-tenancy-example/(托克评论是我)

My SecurityConfigWeb :

public class SecurityConfigWeb extends WebSecurityConfigurerAdapter implements Serializable {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(Constants.URL_PATH2, Constants.URL_PATH3, Constants.URL_PATH4, Constants.URL_PATH5, Constants.URL_PATH6, Constants.URL_PATH7, Constants.CONFIRMATION_EMAIL,
Constants.PATTERN1, Constants.PATHPATTERN2, Constants.PATHPATTERN3, Constants.GET_SYSTEM_URL)
.permitAll().anyRequest().authenticated().and().formLogin().loginPage(Constants.URL_PATH)
.successHandler(this.authSuccess).permitAll().failureHandler(this.authFailure).permitAll().and()
.rememberMe().rememberMeServices(rememberMeServices()).key(Constants.REMEMBER_ME_SECRET_KEY)
.tokenValiditySeconds(86400).and().logout().logoutSuccessUrl(Constants.URL_PATH).and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
....
}

错误:

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/neorchaWEBPlatform] threw exception
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [delete from persistent_logins where username = ?]; SQL state [3D000]; error code [1046]; No database selected; nested exception is java.sql.SQLException: No database selected
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:645)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:866)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:927)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:937)
at org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl.removeUserTokens(JdbcTokenRepositoryImpl.java:114)
at org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices.logout(PersistentTokenBasedRememberMeServices.java:166)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:112)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.sql.SQLException: No database selected
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3976)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3912)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2530)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2683)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2486)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1858)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2079)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2013)
at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5104)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1998)
at org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:87)
at org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:87)
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:873)
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:866)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:629)

任何人都可以帮助我们修复它或提出解决方案吗?.. 提前感谢!

实现,这是解决方案:

在 JdbcTokenRepositoryImpl 上创建JdbcTokenExtend类副本:

package com.lbc.takeoff.neorcha.web;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public class JdbcTokenExtend extends JdbcDaoSupport implements PersistentTokenRepository{  
private boolean createTableOnStartup;
protected void initDao() {
if (createTableOnStartup) {
getJdbcTemplate().execute("create table " + getSchemaName() + ".persistent_logins (username varchar(64) not null, series varchar(64) primary key, "
+ "token varchar(64) not null, last_used timestamp not null)");
}
}
public void createNewToken(PersistentRememberMeToken token) {
getJdbcTemplate().update("insert into " + getSchemaName() + ".persistent_logins (username, series, token, last_used) values(?,?,?,?)", token.getUsername(), token.getSeries(),
token.getTokenValue(), token.getDate());
}
public void updateToken(String series, String tokenValue, Date lastUsed) {
getJdbcTemplate().update("update " + getSchemaName() + ".persistent_logins set token = ?, last_used = ? where series = ?", tokenValue, lastUsed, series);
}
/**
* Loads the token data for the supplied series identifier.
*
* If an error occurs, it will be reported and null will be returned (since the result
* should just be a failed persistent login).
*
* @param seriesId
* @return the token matching the series, or null if no match found or an exception
* occurred.
*/
public PersistentRememberMeToken getTokenForSeries(String seriesId) {
try {
return getJdbcTemplate().queryForObject("select username,series,token,last_used from " + getSchemaName() + ".persistent_logins where series = ?",
new RowMapper<PersistentRememberMeToken>() {
public PersistentRememberMeToken mapRow(ResultSet rs, int rowNum)
throws SQLException {
return new PersistentRememberMeToken(rs.getString(1), rs
.getString(2), rs.getString(3), rs.getTimestamp(4));
}
}, seriesId);
}
catch (EmptyResultDataAccessException zeroResults) {
if (logger.isDebugEnabled()) {
logger.debug("Querying token for series '" + seriesId
+ "' returned no results.", zeroResults);
}
}
catch (IncorrectResultSizeDataAccessException moreThanOne) {
logger.error("Querying token for series '" + seriesId
+ "' returned more than one value. Series" + " should be unique");
}
catch (DataAccessException e) {
logger.error("Failed to load token for series " + seriesId, e);
}
return null;
}
public void removeUserTokens(String username) {
getJdbcTemplate().update("delete from " + getSchemaName() + ".persistent_logins where username = ?", username);
}
/**
* Intended for convenience in debugging. Will create the persistent_tokens database
* table when the class is initialized during the initDao method.
*
* @param createTableOnStartup set to true to execute the
*/
public void setCreateTableOnStartup(boolean createTableOnStartup) {
this.createTableOnStartup = createTableOnStartup;
}
public String getSchemaName() {
// taking the schema name from the schema_name.dns.com
final ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
final HttpServletRequest request = attr.getRequest();
String requestUrl = request.getRequestURL().toString();
String schemaName = requestUrl.substring(requestUrl.lastIndexOf("://") + 3, requestUrl.lastIndexOf(".dns.com"));
return schemaName;
}
}

SecurityConfigWeb中:

/**
* This bean is the JDBC token repository for remember me services.
*/
@Bean
public PersistentTokenRepository persistentTokenRepository() {
//      JdbcTokenRepositoryImpldb = new JdbcTokenRepositoryImpl();  // old code deleted
JdbcTokenExtend db = new JdbcTokenExtend(); // created this java class (copy on JdbcTokenRepositoryImpl)
db.setCreateTableOnStartup(false);
db.setDataSource(dataSource);
return db;
}

此更改解决了该问题,因为现在"从用户名persistent_logins中删除"分配给特定架构名称

最新更新