From 8c69d67816c7d41759736bf5c20a8500b9433950 Mon Sep 17 00:00:00 2001 From: Tang Cheng Date: Thu, 2 Jan 2020 12:54:03 +0800 Subject: [PATCH] =?utf8?q?=E7=A7=BB=E6=A4=8D=20multi-tenant?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- .../framework/core/DayendSettleTask.java | 3 +- .../dlpay/framework/filter/CrosXssFilter.java | 26 ------------ .../framework/filter/ValidateCodeFilter.java | 25 ----------- .../MyAuthenticationSuccessHandler.java | 1 - .../impl/OperatorDetailServiceImpl.java | 28 ++++++++++--- .../com/supwisdom/dlpay/PayApiApplication.kt | 5 +++ .../api/controller/notify_api_controller.kt | 6 +-- .../dlpay/api/scheduler_sourcetype_chk.kt | 7 ++-- .../controller/security_controller.kt | 4 -- .../com/supwisdom/dlpay/framework/tenant.kt | 41 ------------------- .../kotlin/com/supwisdom/dlpay/security.kt | 5 ++- .../src/main/resources/application.properties | 3 +- 13 files changed, 42 insertions(+), 114 deletions(-) delete mode 100644 payapi/src/main/kotlin/com/supwisdom/dlpay/framework/tenant.kt diff --git a/build.gradle b/build.gradle index d863f078..8b61a618 100644 --- a/build.gradle +++ b/build.gradle @@ -102,7 +102,7 @@ subprojects { springSocialVersion = '1.1.6.RELEASE' springKafkaVersion = '2.2.8.RELEASE' postgresVersion = '42.2.5' - multiTenantLibVersion = '1.0.8' + multiTenantLibVersion = '1.1.3' } implementation "org.jetbrains.kotlin:kotlin-reflect" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/core/DayendSettleTask.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/core/DayendSettleTask.java index 37f30ead..1eb9422a 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/framework/core/DayendSettleTask.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/core/DayendSettleTask.java @@ -5,6 +5,7 @@ import com.supwisdom.dlpay.framework.domain.TSettleLog; import com.supwisdom.dlpay.framework.service.DayendSettleService; import com.supwisdom.dlpay.framework.util.Constants; import com.supwisdom.dlpay.framework.util.StringUtil; +import com.supwisdom.multitenant.TenantContextHolder; import com.supwisdom.multitenant.TenantDetailsProvider; import net.javacrumbs.shedlock.core.SchedulerLock; import org.slf4j.Logger; @@ -28,7 +29,7 @@ public class DayendSettleTask { @SchedulerLock(name = "DayendSettleTask", lockAtMostForString = "PT30M") public void doSettleTask() { if (logger.isDebugEnabled()) logger.debug("进入日结算任务!"); - tenantDetailsProvider.defaultTenant(Constants.DEFAULT_TENANTID); + TenantContextHolder.getContext().setTenant(tenantDetailsProvider.defaultTenant()); settleLog = dayendSettleService.doCreateSettleLog(); //记录日志 try { diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/filter/CrosXssFilter.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/filter/CrosXssFilter.java index 632ffde7..ebe49e41 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/framework/filter/CrosXssFilter.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/filter/CrosXssFilter.java @@ -1,18 +1,12 @@ package com.supwisdom.dlpay.framework.filter; -import com.google.gson.Gson; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebFilter public class CrosXssFilter implements Filter { - private static final Logger logger = LoggerFactory.getLogger(CrosXssFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { @@ -21,31 +15,11 @@ public class CrosXssFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - request.setCharacterEncoding("utf-8"); - - //跨域设置 -// if(response instanceof HttpServletResponse){ -// HttpServletResponse httpServletResponse=(HttpServletResponse)response; -// //通过在响应 header 中设置 ‘*’ 来允许来自所有域的跨域请求访问。 -// httpServletResponse.setHeader("Access-Control-Allow-Origin", "*"); -// //通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie -// //设置了Allow-Credentials,Allow-Origin就不能为*,需要指明具体的url域 -// //httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true"); -// //请求方式 -// httpServletResponse.setHeader("Access-Control-Allow-Methods", "*"); -// //(预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被缓存多久 -// httpServletResponse.setHeader("Access-Control-Max-Age", "86400"); -// //首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段 -// httpServletResponse.setHeader("Access-Control-Allow-Headers", "*"); -// } - //sql,xss过滤 HttpServletRequest httpServletRequest = (HttpServletRequest) request; -// logger.info("CrosXssFilter.......orignal url:{},ParameterMap:{}", httpServletRequest.getRequestURI(), new Gson().toJson(httpServletRequest.getParameterMap())); XssHttpServletRequestWrapper xssHttpServletRequestWrapper = new XssHttpServletRequestWrapper( httpServletRequest); chain.doFilter(xssHttpServletRequestWrapper, response); -// logger.info("CrosXssFilter..........doFilter url:{},ParameterMap:{}", xssHttpServletRequestWrapper.getRequestURI(), new Gson().toJson(xssHttpServletRequestWrapper.getParameterMap())); } @Override diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java index c58260d8..e2340662 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java @@ -49,10 +49,6 @@ public class ValidateCodeFilter extends OncePerRequestFilter { try { validate(request); } catch (ValidateCodeException e) { - //response.setStatus(HttpStatus.OK.value()); - //response.setContentType("application/json;charset=UTF-8"); - //response.getWriter().write(objectMapper.writeValueAsString(JsonResult.error(400, e.getMessage()))); - //response.sendError(HttpStatus.UNAUTHORIZED.value(),e.getMessage()); myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e); return; } @@ -66,27 +62,6 @@ public class ValidateCodeFilter extends OncePerRequestFilter { } else { request.getSession().removeAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY); } -// VerifyCode imageCode = (VerifyCode) request.getSession().getAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY); -// String inputCode; -// try { -// inputCode = request.getParameter("imageCode"); -// } catch (Exception e) { -// throw new ValidateCodeException("获取验证码的值失败"); -// } -// if (StringUtil.isEmpty(inputCode)) { -// throw new ValidateCodeException("验证码不能为空"); -// } -// if (null == imageCode) { -// throw new ValidateCodeException("验证码不存在"); -// } -// if (imageCode.isExpired()) { -// request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY); -// throw new ValidateCodeException("验证码已过期"); -// } -// if (!StringUtil.equalsIgnoreCase(imageCode.getText(), inputCode)) { -// throw new ValidateCodeException("验证码不匹配"); -// } -// request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY); } } diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java index abaa46a0..f74d15da 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java @@ -5,7 +5,6 @@ import com.supwisdom.dlpay.api.bean.JsonResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.stereotype.Component; diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java index 755828d2..88f2121d 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java @@ -5,7 +5,9 @@ import com.supwisdom.dlpay.framework.dao.OperatorDao; import com.supwisdom.dlpay.framework.domain.TOperator; import com.supwisdom.dlpay.framework.service.OperatorDetailService; import com.supwisdom.dlpay.framework.util.StringUtil; -import org.springframework.beans.factory.annotation.Autowired; +import com.supwisdom.multitenant.TenantDetails; +import com.supwisdom.multitenant.TenantSessionHelper; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetails; @@ -16,16 +18,30 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import static org.apache.commons.lang3.StringUtils.substringAfter; +import static org.apache.commons.lang3.StringUtils.substringBefore; + + +@Slf4j @Service public class OperatorDetailServiceImpl implements OperatorDetailService { - @Autowired - private OperatorDao operatorDao; - @Autowired - private OperRoleDao operRoleDao; + private final OperatorDao operatorDao; + private final OperRoleDao operRoleDao; + private final TenantSessionHelper tenantSessionHelper; + + public OperatorDetailServiceImpl(OperatorDao operatorDao, OperRoleDao operRoleDao, + TenantSessionHelper tenantSessionHelper) { + this.operatorDao = operatorDao; + this.operRoleDao = operRoleDao; + this.tenantSessionHelper = tenantSessionHelper; + } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - TOperator oper = operatorDao.findByOpercode(username); + String domain = substringAfter(username, "@"); + tenantSessionHelper.setSessionTenantById(domain); + String realname = substringBefore(username, "@"); + TOperator oper = operatorDao.findByOpercode(realname); if (null == oper) { throw new UsernameNotFoundException("管理员不存在"); } diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt index a4223911..4b88ed02 100644 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt @@ -5,6 +5,7 @@ import com.supwisdom.dlpay.framework.tenant.TenantCacheKeyGen import com.supwisdom.dlpay.framework.util.Constants import com.supwisdom.multitenant.TenantDetails import com.supwisdom.multitenant.TenantDetailsProvider +import com.supwisdom.multitenant.TenantSessionData import com.supwisdom.multitenant.annotations.EnableHttpHeaderTenantInterceptor import com.supwisdom.multitenant.annotations.EnableSessionTenantInterceptor import io.lettuce.core.ReadFrom @@ -178,6 +179,10 @@ class MyTenantDetailsProvider : TenantDetailsProvider { dataCenter = "default" } + override fun defaultTenant(): TenantDetails { + return defaultTenant + } + override fun createDetailsById(id: String?): TenantDetails { return tenantService.findByTenantId(id)?.let { catalog -> TenantDetails().apply { diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/notify_api_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/notify_api_controller.kt index e5787940..8b382386 100644 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/notify_api_controller.kt +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/notify_api_controller.kt @@ -36,7 +36,7 @@ class NotifyController { fun index(@PathVariable schema: String, request: HttpServletRequest, response: HttpServletResponse): String { logger.error("====================== 收到微信回调通知 wechat notify: ========================") - tenantDetailsProvider.defaultTenant(schema) + TenantContextHolder.getContext().tenant = tenantDetailsProvider.createDetailsById(schema) try { // 解析结果存储在HashMap var map: MutableMap = HashMap() @@ -47,7 +47,7 @@ class NotifyController { // 得到xml根元素 val root = document.rootElement // 得到根元素的所有子节点 - val elementList = root.elements() as MutableList + val elementList = root.elements() as MutableList // 遍历所有子节点 for (e in elementList) { map[e.name] = e.text @@ -90,7 +90,7 @@ class NotifyController { fun alipay(@PathVariable schema: String, request: HttpServletRequest, response: HttpServletResponse): String { logger.error("====================== 收到支付宝回调通知 alipay notify: ========================") - tenantDetailsProvider.defaultTenant(schema) + TenantContextHolder.getContext().tenant = tenantDetailsProvider.createDetailsById(schema) // 解析结果存储在HashMap val map = makeMapFromParam(request) val resp = alipayService.doNotify(map) diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_sourcetype_chk.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_sourcetype_chk.kt index 33d9a729..e3ab9e49 100644 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_sourcetype_chk.kt +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_sourcetype_chk.kt @@ -14,6 +14,7 @@ import com.supwisdom.dlpay.framework.service.SystemUtilService import com.supwisdom.dlpay.framework.util.Constants import com.supwisdom.dlpay.framework.util.DateUtil import com.supwisdom.dlpay.util.ConstantUtil +import com.supwisdom.multitenant.TenantContextHolder import com.supwisdom.multitenant.TenantDetailsProvider import mu.KotlinLogging import net.javacrumbs.shedlock.core.SchedulerLock @@ -162,7 +163,7 @@ class SourceTypeCheck { @Scheduled(cron = "\${payapi.sourcetype.checker.scheduler:-}") @SchedulerLock(name = "payapiSourceTypeCheckLock", lockAtMostForString = "PT30M") fun runCheck() { - tenantDetailsProvider.defaultTenant(Constants.DEFAULT_TENANTID) + TenantContextHolder.getContext().tenant = tenantDetailsProvider.defaultTenant() val allSourcetype = sourceTypeService.allEnabledSourcetype ?: return @@ -276,7 +277,7 @@ class SourceTypeCheckExecutor { fun checkAndDownloadChkfile(checkStatus: TSourceTypeCheckStatus): Future { // 2. 根据对账日期下载对账文件 try { - tenantDetailsProvider.defaultTenant(Constants.DEFAULT_TENANTID) + TenantContextHolder.getContext().tenant = tenantDetailsProvider.defaultTenant() if (checkStatus.settleStatus) { return AsyncResult(ExecutorResult(checkStatus, FAIL, "[${checkStatus.checkAccdate}]日对账已完成")) } @@ -319,7 +320,7 @@ class SourceTypeCheckExecutor { @Async("sourcetypeCheckTaskExecutor") fun reconciliation(checkStatus: TSourceTypeCheckStatus): Future { // 3. 完成对账 - tenantDetailsProvider.defaultTenant(Constants.DEFAULT_TENANTID) + TenantContextHolder.getContext().tenant = tenantDetailsProvider.defaultTenant() if (!checkStatus.checkFileOk) { return AsyncResult(ExecutorResult(checkStatus, FAIL, "checkAccdate=[${checkStatus.checkAccdate}]对账单未完成下载,不能对账")) } else if (checkStatus.settleStatus) { diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt index ed5783f3..deabb415 100644 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt @@ -21,16 +21,13 @@ import com.supwisdom.dlpay.framework.service.SystemUtilService import com.supwisdom.dlpay.framework.util.* import com.supwisdom.dlpay.system.service.FunctionService import mu.KotlinLogging -import org.jose4j.jwt.ReservedClaimNames import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.redis.connection.RedisConnectionFactory import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity -import org.springframework.security.core.Authentication import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.core.userdetails.UserDetails -import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper import org.springframework.security.oauth2.provider.OAuth2Authentication import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler @@ -40,7 +37,6 @@ import org.springframework.ui.Model import org.springframework.web.bind.annotation.* import org.springframework.web.context.request.ServletWebRequest import java.io.IOException -import java.security.Principal import java.util.* import javax.imageio.ImageIO import javax.servlet.http.HttpServletRequest diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/tenant.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/tenant.kt deleted file mode 100644 index b9b60342..00000000 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/tenant.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.supwisdom.dlpay.framework - -import mu.KotlinLogging -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.context.annotation.Configuration -import org.springframework.web.servlet.config.annotation.InterceptorRegistry -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer -import javax.annotation.PostConstruct - - -//@Order(1) -//@WebFilter(filterName = "multi_tenant_filter", urlPatterns = ["/*"]) -//class TenantNameFilter : Filter { -// override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) { -// if (request is HttpServletRequest) { -// request.getHeader(Constants.HEADER_TETANTID)?.also { -// // set tanent datasource -// TenantContext.setTenantSchema(it) -// } ?: TenantContext.setTenantSchema("default") -// } -// chain.doFilter(request, response) -// } -//} - -//@Configuration -//class MultiTenantDatasourceConfiguration : WebMvcConfigurer { -// -// private val logger = KotlinLogging.logger { } -// @Autowired -// private lateinit var tenantInterceptor: TenantInterceptor -// -// @PostConstruct -// fun post() { -// logger.info("MultiTenantDatasourceConfiguration post constructor.") -// } -// -// override fun addInterceptors(registry: InterceptorRegistry) { -// logger.info("adding interceptor(s).") -// registry.addInterceptor(tenantInterceptor) -// } -//} diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/security.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/security.kt index ee4a5c69..61c805ff 100644 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/security.kt +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/security.kt @@ -231,6 +231,7 @@ class WebSecurityConfig { class ApiWebSecurityConfigurationAdapter : WebSecurityConfigurerAdapter() { @Autowired lateinit var apiJwtAuthenticationFilter: ApiJwtAuthenticationFilter + override fun configure(http: HttpSecurity) { // 设置 API 访问权限管理 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) @@ -374,14 +375,14 @@ class WebSecurityConfig { http.apply(validateCodeSecurityConfig) .and() .authorizeRequests() - .antMatchers("/login", "/login/form", "/mobileapi/**","/userinfor").permitAll() + .antMatchers("/login", "/login/form", "/mobileapi/**", "/userinfor").permitAll() .antMatchers("/static/**").permitAll() .antMatchers("/code/image").permitAll() .antMatchers("/**").hasAnyRole("USER", "ADMIN") .anyRequest().authenticated() .and() .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .and() .formLogin() .loginPage("/login") diff --git a/payapi/src/main/resources/application.properties b/payapi/src/main/resources/application.properties index 8627bf06..906a5bec 100644 --- a/payapi/src/main/resources/application.properties +++ b/payapi/src/main/resources/application.properties @@ -42,5 +42,6 @@ auth.password.bcrypt.length=10 spring.redis.database=0 ################################################### multi-tenant.header.key=X-TENANT-ID -multi-tenant.session.name=multi-tenant-id +multi-tenant.session.name=tenant-id +multi-tenant.session.enableSessionScopedBean=false multi-tenant.dbschema=public -- 2.17.1