SpringBoot身份验证数据源
我在应用程序中使用SpringBoot、SpringSecurity、C3P0和JPA hibernate 如何让SpringBoot尝试使用与.properties文件中提供的数据源不同的数据源对用户进行身份验证 编辑1SpringBoot身份验证数据源,spring,hibernate,spring-security,spring-boot,c3p0,Spring,Hibernate,Spring Security,Spring Boot,C3p0,我在应用程序中使用SpringBoot、SpringSecurity、C3P0和JPA hibernate 如何让SpringBoot尝试使用与.properties文件中提供的数据源不同的数据源对用户进行身份验证 编辑1 public class AuthFilter extends AbstractAuthenticationProcessingFilter { private boolean postOnly = true; public AuthFilter() {
public class AuthFilter extends AbstractAuthenticationProcessingFilter {
private boolean postOnly = true;
public AuthFilter() {
super(new AntPathRequestMatcher("/login", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: "
+ request.getMethod());
}
String email = request.getParameter("username");
String password = request.getParameter("password");
String username = email.substring(0, email.indexOf("@"));
String db = email.substring(email.indexOf("@") + 1, email.lastIndexOf("."));
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Here I should change the DataSource before the authentication occurs.
return this.getAuthenticationManager().authenticate(authRequest);
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
}
OP解决方案
我在我的AuthenticationProvider
中为客户端创建了一个sessionFactory
和一个数据源,并手动搜索他,而不是使用我的服务。成功了
如果您需要使用不同的系统,您可以使用ReST模板在自定义authenticationProvider中调用API。因此,通过ReST API,您可以进行身份验证。像这样的事情,
public static final String REST_SERVICE_URI = "<your microservice end
point>";
Users authApiObj = new Users();
authApiObj.username = "username";
authApiObj.password = "username";
RestTemplate restTemplate = new RestTemplate();
HttpEntity<Object> request = new HttpEntity<Object>(authApiObj, headers);
String responseString = restTemplate.postForObject(REST_SERVICE_URI,
request, String.class);
公共静态最终字符串REST_SERVICE_URI=”“;
Users authApiObj=新用户();
authApiObj.username=“username”;
authApiObj.password=“用户名”;
RestTemplate RestTemplate=新RestTemplate();
HttpEntity请求=新的HttpEntity(authApiObj,头文件);
String responseString=restTemplate.postForObject(REST\u服务\u URI,
请求,String.class);
否则,您需要配置spring cloud config server并启动您的spring boot应用程序(可选),并从已配置的spring config server访问应用程序中加载的动态属性;但可能会帮助其他人寻找答案(答案可能有点长) 注意:以下逻辑不会切换到同一请求中的多个DB源。JPA连接到
application.properties
文件中指向的主数据源。下面的逻辑只是使用JDBC模板进行额外的数据库连接
SpringBoot 2.0.1引入了一种可以根据请求动态使用适当数据源的方法。datasource
的类型为Map
本质上,数据源映射应该包含连接标识符作为键,数据源作为值。有两种方法可以填充地图
第1种方式:此处仅在应用程序启动时填充dataSourceMap。(假设所有用户都存在于不同的单个数据库中(主数据库除外),此方法就足够了。)
a。创建一个配置文件ClientDataSourceConfig.java
,该文件在应用程序启动时加载,其中dataSourceMap是手动准备的,并为JPA设置默认目标DB源
ClientDataSourceConfig.java:
import com.company.tripmis.datasource.ClientDataSourceRouter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ClientDataSourceConfig {
@Value("${spring.datasource.driver}")
private String driver;
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
public ClientDataSourceRouter dataSource;
@Bean(name = "getDataSource") // <-- IMP: Bean and Returning manually created ClientDataSourceRouter
public ClientDataSourceRouter getDataSource() throws Exception {
dataSource = new ClientDataSourceRouter();
// Here we are initialising default DB from application.properties file manually.
dataSource.init(driver, url, username, password);
return dataSource;
}
}
第二种方法:为了动态更新dataSourceMap,创建一个过滤器,它将在每次请求时从DB读取数据,并更新相同的数据。(应使用相同的方法,以便不会在每次请求时命中DB,并定期更新CacheBucket。)
既然在应用程序启动时向datasourceMap添加了多个DB连接,那么我们需要做的就是在需要时使用JDBCTemplate
连接进行用户身份验证
这可以通过使用过滤器或HttpInterceptor拦截HttpRequest来完成,也可以根据需要在控制器
/服务
层进行拦截
下面的伪代码在过滤器
级别执行身份验证
import java.io.IOException;
import java.util.HashMap;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import com.company.tripmis.datasource.ClientDataSourceContext;
import com.company.tripmis.datasource.ClientDataSourceRouter;
import com.company.tripmis.model.pojo.ErrorModel;
import com.company.tripmis.model.pojo.ResponseModel;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
@Order(2)
public class RequestDataSourceFilter implements Filter {
@Autowired
private ApplicationContext applicationContext;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String companyId = httpRequest.getRequestURI().split("/")[1];
ClientDataSourceRouter clientDataSourceRouterObj = (ClientDataSourceRouter) applicationContext
.getBean("getDataSource");
HashMap<Object, Object> dataSourcesMap = clientDataSourceRouterObj.getDataSources();
// Some of the following code is for MultiTenant, if not needed, please ignore
if (dataSourcesMap.get(companyId) == null) {
ResponseModel responseModel = new ResponseModel();
ErrorModel errorModel = new ErrorModel();
errorModel.setCode("DB_RES_NOT_FND");
errorModel.setMessage("The DB schema mapping not found for the given: " + companyId);
responseModel.setSuccess(false);
responseModel.setMessage("Requested DB resource not found");
responseModel.setError(errorModel);
((HttpServletResponse) response).setHeader("Content-Type", "application/json");
((HttpServletResponse) response).setStatus(400);
response.getOutputStream().write(new ObjectMapper().writeValueAsString(responseModel).getBytes());
return;
} else {
String username = ""; // Read username from request
JdbcTemplate jdbcTemplate = new JdbcTemplate((DataSource) dataSourcesMap.get(companyId));
String sqlQuery = "select * from user where username = ?";
// Prepare the query
List<Model> userList = jdbcTemplate.query(sqlQuery, new Object[] { username },
new UserAuthMapper());
// Replace with proper query and create a custom mapper as required.
// And continue with the authentication here.
}
ClientDataSourceContext.setClientName(companyId);
chain.doFilter(request, response);
}
}
import java.io.IOException;
导入java.util.HashMap;
导入javax.servlet.Filter;
导入javax.servlet.FilterChain;
导入javax.servlet.ServletException;
导入javax.servlet.ServletRequest;
导入javax.servlet.ServletResponse;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
导入javax.sql.DataSource;
导入com.company.tripmis.datasource.ClientDataSourceContext;
导入com.company.tripmis.datasource.clientdatasourceouter;
导入com.company.tripmis.model.pojo.ErrorModel;
导入com.company.tripmis.model.pojo.ResponseModel;
导入com.fasterxml.jackson.databind.ObjectMapper;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.context.ApplicationContext;
导入org.springframework.core.annotation.Order;
导入org.springframework.jdbc.core.jdbc模板;
导入org.springframework.stereotype.Component;
@组成部分
@订单(2)
公共类RequestDataSourceFilter实现筛选器{
@自动连线
私有应用程序上下文应用程序上下文;
@凌驾
public void doFilter(ServletRequest请求、ServletResponse响应、FilterChain链)
抛出IOException、ServletException{
HttpServletRequest httpRequest=(HttpServletRequest)请求;
字符串companyId=httpRequest.getRequestURI().split(“/”[1];
ClientDataSourceRouter clientDataSourceRouterObj=(ClientDataSourceRouter)应用程序上下文
.getBean(“getDataSource”);
HashMap dataSourcesMap=clientDataSourceRouterObj.getDataSources();
//以下部分代码适用于多租户,如果不需要,请忽略
if(dataSourcesMap.get(companyId)==null){
ResponseModel ResponseModel=新的ResponseModel();
ErrorModel ErrorModel=新的ErrorModel();
errorModel.setCode(“DB_RES_NOT_FND”);
errorModel.setMessage(“找不到给定:“+companyId”)的DB架构映射);
responseModel.setSuccess(假);
setMessage(“未找到请求的数据库资源”);
responseModel.setError(errorModel);
setHeader(“内容类型”、“应用程序/json”);
((HttpServletResponse)响应);
response.getOutputStream().write(新的ObjectMapper().writeValueAsString(responseModel.getBytes());
返回;
}否则{
字符串username=”“;//从请求读取用户名
JdbcTemplate JdbcTemplate=newjdbctemplate((数据源)dataSourcesMap.get(companyId));
String sqlQuery=“select*from user where username=?”;
//准备查询
List userList=jdbcTemplate.query(sqlQuery,新对象[]{username},
新的UserAuthMapper());
//替换为正确的查询和cre
import java.io.IOException;
import java.util.HashMap;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import com.company.tripmis.datasource.ClientDataSourceContext;
import com.company.tripmis.datasource.ClientDataSourceRouter;
import com.company.tripmis.model.pojo.ErrorModel;
import com.company.tripmis.model.pojo.ResponseModel;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
@Order(2)
public class RequestDataSourceFilter implements Filter {
@Autowired
private ApplicationContext applicationContext;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String companyId = httpRequest.getRequestURI().split("/")[1];
ClientDataSourceRouter clientDataSourceRouterObj = (ClientDataSourceRouter) applicationContext
.getBean("getDataSource");
HashMap<Object, Object> dataSourcesMap = clientDataSourceRouterObj.getDataSources();
// Some of the following code is for MultiTenant, if not needed, please ignore
if (dataSourcesMap.get(companyId) == null) {
ResponseModel responseModel = new ResponseModel();
ErrorModel errorModel = new ErrorModel();
errorModel.setCode("DB_RES_NOT_FND");
errorModel.setMessage("The DB schema mapping not found for the given: " + companyId);
responseModel.setSuccess(false);
responseModel.setMessage("Requested DB resource not found");
responseModel.setError(errorModel);
((HttpServletResponse) response).setHeader("Content-Type", "application/json");
((HttpServletResponse) response).setStatus(400);
response.getOutputStream().write(new ObjectMapper().writeValueAsString(responseModel).getBytes());
return;
} else {
String username = ""; // Read username from request
JdbcTemplate jdbcTemplate = new JdbcTemplate((DataSource) dataSourcesMap.get(companyId));
String sqlQuery = "select * from user where username = ?";
// Prepare the query
List<Model> userList = jdbcTemplate.query(sqlQuery, new Object[] { username },
new UserAuthMapper());
// Replace with proper query and create a custom mapper as required.
// And continue with the authentication here.
}
ClientDataSourceContext.setClientName(companyId);
chain.doFilter(request, response);
}
}