引入 multi-tenant library 并完成初步测试
diff --git a/build.gradle b/build.gradle
index 8b61a61..6f3c4df 100644
--- a/build.gradle
+++ b/build.gradle
@@ -102,7 +102,7 @@
             springSocialVersion = '1.1.6.RELEASE'
             springKafkaVersion = '2.2.8.RELEASE'
             postgresVersion = '42.2.5'
-            multiTenantLibVersion = '1.1.3'
+            multiTenantLibVersion = '1.1.17'
         }
         implementation "org.jetbrains.kotlin:kotlin-reflect"
         implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
diff --git a/config/application-devel-pg-local.properties b/config/application-devel-pg-local.properties
index 1c33450..3d596e3 100644
--- a/config/application-devel-pg-local.properties
+++ b/config/application-devel-pg-local.properties
@@ -25,6 +25,7 @@
 ##################################################
 ## quartz task scheduler
 shopbalance.updater.cron=-
+payapi.sourcetype.checker.scheduler=* * * * * ?
 #############################################
 spring.cloud.consul.enabled=false
 spring.cloud.consul.host=172.28.201.70
diff --git a/config/application-devel-pg-touchorder.properties b/config/application-devel-pg-touchorder.properties
new file mode 100644
index 0000000..fc790a9
--- /dev/null
+++ b/config/application-devel-pg-touchorder.properties
@@ -0,0 +1,60 @@
+spring.main.banner-mode=off
+# create and drop tables and sequences, loads import.sql
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
+spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
+#spring.jpa.properties.hibernate.default_schema=public
+spring.datasource.continue-on-error=true
+spring.datasource.initialization-mode=always
+# Postgresql settings
+spring.datasource.platform=postgresql
+spring.datasource.url=jdbc:postgresql://172.28.201.70:15432/touchorder
+spring.datasource.username=payapi
+spring.datasource.password=123456
+logging.level.org.hibernate.SQL=DEBUG
+logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
+logging.level.com.supwisdom.dlpay=DEBUG
+# Redis settings
+spring.redis.host=172.28.201.70
+spring.redis.port=2379
+spring.redis.password=kingstar
+# jwt settings
+jwt.secret=Zj5taLomEbrM0lk+NMQZbHfSxaDU1wekjT+kiC3YzDw=
+# timeout seconds
+jwt.expiration=3600
+# user password
+auth.password.bcrypt.seed=
+security.request.sign=false
+##################################################
+## quartz task scheduler
+shopbalance.updater.cron=-
+#############################################
+spring.cloud.consul.enabled=false
+spring.cloud.consul.host=172.28.201.70
+spring.cloud.consul.port=8500
+resttemplate.proxy.type=http
+resttemplate.proxy.host=127.0.0.1
+resttemplate.proxy.port=1087
+
+#============== kafka ===================
+# 指定kafka 代理地址,可以多个
+spring.kafka.bootstrap-servers=172.28.201.101:9192
+#=============== provider  =======================
+spring.kafka.producer.retries=3
+# 每次批量发送消息的数量
+spring.kafka.producer.batch-size=16384
+spring.kafka.producer.buffer-memory=33554432
+# 指定消息key和消息体的编解码方式
+spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
+spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
+
+#===============kafka consumer  =======================
+# 指定默认消费者group id
+spring.kafka.listen.auto.start=false
+spring.kafka.consumer.group-id=epaymessager1
+spring.kafka.consumer.auto-offset-reset=earliest
+spring.kafka.consumer.enable-auto-commit=true
+spring.kafka.consumer.auto-commit-interval=100
+# 指定消息key和消息体的编解码方式
+spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
+spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
\ No newline at end of file
diff --git a/payapi-sdk/build.gradle b/payapi-sdk/build.gradle
index ecd7869..53c76f1 100644
--- a/payapi-sdk/build.gradle
+++ b/payapi-sdk/build.gradle
@@ -24,8 +24,20 @@
     enabled = false
 }
 
+repositories {
+    maven {
+        url "http://ykt-nx.supwisdom.com/repository/ecard-repo/"
+        credentials {
+            username "${nxUser}"
+            password "${nxPassword}"
+        }
+    }
+}
+
 dependencies {
     implementation project(":payapi-common")
+    implementation "com.supwisdom:multi-tenant-core:${multiTenantLibVersion}"
+    compile "com.supwisdom:multi-tenant-jwt-client:${multiTenantLibVersion}"
 
     implementation "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
     implementation "org.springframework.cloud:spring-cloud-starter-openfeign"
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/ApiLoginHelper.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/ApiLoginHelper.java
index 378bf1b..9c10a7e 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/ApiLoginHelper.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/ApiLoginHelper.java
@@ -4,8 +4,10 @@
 import com.supwisdom.dlpay.api.bean.ApiLoginResponse;
 import com.supwisdom.dlpay.api.util.HMACUtil;
 import com.supwisdom.dlpay.paysdk.proxy.ApiLoginProxy;
-import com.supwisdom.dlpay.paysdk.utils.JwtContext;
 
+/**
+ * @deprecated 1.1
+ */
 public class ApiLoginHelper {
   private ApiLoginProxy apiLoginProxy;
 
@@ -37,7 +39,6 @@
     if (login.getRetcode() != 0) {
       throw new RuntimeException("登录错误: " + loginInit.getRetcode() + ", " + loginInit.getException());
     }
-    JwtContext.setJwt(login.getJwt());
   }
 
   public void refresh() {
@@ -45,6 +46,5 @@
     if (response.getRetcode() != 0) {
       throw new RuntimeException("刷新JWT错误: " + response.getRetcode() + ", " + response.getException());
     }
-    JwtContext.setJwt(response.getJwt());
   }
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/MultiTenantAutoConfig.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/MultiTenantAutoConfig.java
deleted file mode 100644
index f849cea..0000000
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/MultiTenantAutoConfig.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.supwisdom.dlpay.paysdk;
-
-import com.supwisdom.dlpay.paysdk.tenant.DefaultMultiTenantProviderFactory;
-import com.supwisdom.dlpay.paysdk.tenant.MultiTenantProviderFactory;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class MultiTenantAutoConfig {
-  @Bean
-  @ConditionalOnMissingBean(MultiTenantProviderFactory.class)
-  public MultiTenantProviderFactory defaultFactory() {
-    return new DefaultMultiTenantProviderFactory();
-  }
-}
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayAPIRequestInterceptor.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayAPIRequestInterceptor.java
index 0a11f39..604d9ff 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayAPIRequestInterceptor.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayAPIRequestInterceptor.java
@@ -1,40 +1,40 @@
 package com.supwisdom.dlpay.paysdk;
 
-import com.supwisdom.dlpay.paysdk.tenant.MultiTenantProviderFactory;
 import com.supwisdom.dlpay.paysdk.utils.Constants;
-import com.supwisdom.dlpay.paysdk.utils.JwtContext;
+import com.supwisdom.mutlitenant.client.JwtTokenClientManager;
+import com.supwisdom.mutlitenant.client.JwtTokenMetadata;
+import com.supwisdom.mutlitenant.client.config.JwtTenantAuthentication;
 import feign.RequestInterceptor;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.stereotype.Component;
 
+import java.util.Optional;
+
 @Component
 public class PayAPIRequestInterceptor {
 
+  private final JwtTokenClientManager manager;
+
+  public PayAPIRequestInterceptor(JwtTokenClientManager manager) {
+    this.manager = manager;
+  }
+
   @Value("${payapi.tenantid:}")
   private String tenantid;
 
-  private final MultiTenantProviderFactory tenantProviderFactory;
-
-  public PayAPIRequestInterceptor(MultiTenantProviderFactory tenantProviderFactory) {
-    this.tenantProviderFactory = tenantProviderFactory;
-  }
 
   @Bean
   public RequestInterceptor headerInterceptor() {
     return requestTemplate -> {
-      // 小示例,没什么卵用
-      String tenant;
-      if (tenantid != null || "".equals(tenantid)) {
-        tenant = tenantProviderFactory.getProvider().getCurrentTenant();
-      } else {
-        tenant = tenantid;
-      }
-      requestTemplate.header(Constants.HEADER_TENANT_ID, tenant);
-      String jwt = JwtContext.getJwt();
-      if (jwt != null) {
-        requestTemplate.header(Constants.JWT_HEADER, "Bearer " + jwt);
-      }
+      Optional<JwtTenantAuthentication> authentication = manager.currentContextTenantAuthentication();
+      requestTemplate.header(Constants.HEADER_TENANT_ID, tenantid);
+      authentication.ifPresent(jwtTenantAuthentication ->
+          requestTemplate.header(Constants.HEADER_TENANT_ID, jwtTenantAuthentication.getTenantId()));
+
+      Optional<JwtTokenMetadata> metadata = manager.currentContextJwtTokenMetadata();
+      metadata.ifPresent(jwtTokenMetadata -> requestTemplate.header(jwtTokenMetadata.getHttpHeader(),
+          jwtTokenMetadata.getSchema() + " " + jwtTokenMetadata.getToken()));
     };
   }
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayAPISDKConfigure.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayAPISDKConfigure.java
new file mode 100644
index 0000000..a4d6790
--- /dev/null
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayAPISDKConfigure.java
@@ -0,0 +1,24 @@
+package com.supwisdom.dlpay.paysdk;
+
+import com.supwisdom.dlpay.paysdk.impl.PaySDKJwtTokenCallback;
+import com.supwisdom.dlpay.paysdk.proxy.ApiLoginProxy;
+import com.supwisdom.mutlitenant.client.JwtTokenClientCallback;
+import com.supwisdom.mutlitenant.client.annotations.EnableTenantJwtClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.stereotype.Component;
+
+@Component
+@EnableTenantJwtClient
+public class PayAPISDKConfigure {
+  @Bean
+  public JwtTokenClientCallback jwtTokenClientCallback(ApiLoginProxy loginProxy) {
+    return new PaySDKJwtTokenCallback(loginProxy);
+  }
+
+  @Bean
+  @DependsOn("jwtTokenClientCallback")
+  public PayApiJwtClientConfigure jwtClientConfigure(JwtTokenClientCallback callback) {
+    return new PayApiJwtClientConfigure(callback);
+  }
+}
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayApiJwtClientConfigure.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayApiJwtClientConfigure.java
new file mode 100644
index 0000000..125fb10
--- /dev/null
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/PayApiJwtClientConfigure.java
@@ -0,0 +1,18 @@
+package com.supwisdom.dlpay.paysdk;
+
+import com.supwisdom.mutlitenant.client.JwtClientConfigure;
+import com.supwisdom.mutlitenant.client.JwtClientConfigureAdapter;
+import com.supwisdom.mutlitenant.client.JwtTokenClientCallback;
+
+public class PayApiJwtClientConfigure implements JwtClientConfigureAdapter {
+  private final JwtTokenClientCallback callback;
+
+  public PayApiJwtClientConfigure(JwtTokenClientCallback callback) {
+    this.callback = callback;
+  }
+
+  @Override
+  public void configure(JwtClientConfigure configure) {
+    configure.registerCallback(callback);
+  }
+}
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/impl/PaySDKJwtTokenCallback.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/impl/PaySDKJwtTokenCallback.java
new file mode 100644
index 0000000..8719384
--- /dev/null
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/impl/PaySDKJwtTokenCallback.java
@@ -0,0 +1,61 @@
+package com.supwisdom.dlpay.paysdk.impl;
+
+import com.supwisdom.dlpay.api.bean.ApiLoginInitResponse;
+import com.supwisdom.dlpay.api.bean.ApiLoginResponse;
+import com.supwisdom.dlpay.api.util.HMACUtil;
+import com.supwisdom.dlpay.paysdk.proxy.ApiLoginProxy;
+import com.supwisdom.dlpay.paysdk.utils.Constants;
+import com.supwisdom.mutlitenant.client.JwtTokenClientCallback;
+import com.supwisdom.mutlitenant.client.JwtTokenMetadata;
+import com.supwisdom.mutlitenant.client.config.JwtTenantAuthentication;
+import org.springframework.util.StringUtils;
+
+import java.time.Instant;
+import java.util.Optional;
+
+public class PaySDKJwtTokenCallback implements JwtTokenClientCallback {
+  private final ApiLoginProxy apiLoginProxy;
+
+  public PaySDKJwtTokenCallback(ApiLoginProxy apiLoginProxy) {
+    this.apiLoginProxy = apiLoginProxy;
+
+  }
+
+  private Optional<JwtTokenMetadata> getTokenResponse(ApiLoginResponse response) {
+    if (response.getRetcode() != 0) {
+      throw new RuntimeException("登录错误: " + response.getRetcode() + ", " + response.getException());
+    }
+    Instant expiration = Instant.parse(response.getExpiredAt());
+    return Optional.of(new JwtTokenMetadata(response.getJwt(),
+        Constants.JWT_HEADER, Constants.JWT_SCHEMA, expiration.getEpochSecond()));
+  }
+
+  @Override
+  public Optional<JwtTokenMetadata> execute(JwtTenantAuthentication authentication) {
+    ApiLoginInitResponse loginInit;
+    boolean withClientId = (authentication.getClientId() != null &&
+        !StringUtils.isEmpty(authentication.getClientId()));
+    if (withClientId) {
+      loginInit = apiLoginProxy.loginInitWithClientId(authentication.getAppId(), authentication.getClientId());
+    } else {
+      loginInit = apiLoginProxy.loginInit(authentication.getAppId());
+    }
+    if (loginInit.getRetcode() != 0) {
+      throw new RuntimeException("登录初始化错误: " + loginInit.getRetcode() + ", " + loginInit.getException());
+    }
+    String token = HMACUtil.sha256HMAC(loginInit.getToken(), authentication.getSecret());
+    ApiLoginResponse login;
+    if (withClientId) {
+      login = apiLoginProxy.loginWithClientId(authentication.getAppId(), token, authentication.getClientId());
+    } else {
+      login = apiLoginProxy.login(authentication.getAppId(), token);
+    }
+    return getTokenResponse(login);
+  }
+
+  @Override
+  public Optional<JwtTokenMetadata> refresh(JwtTokenMetadata old) {
+    ApiLoginResponse response = apiLoginProxy.refresh();
+    return getTokenResponse(response);
+  }
+}
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ApiLoginProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ApiLoginProxy.java
index f564a00..c8b8761 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ApiLoginProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ApiLoginProxy.java
@@ -2,6 +2,7 @@
 
 import com.supwisdom.dlpay.api.bean.ApiLoginInitResponse;
 import com.supwisdom.dlpay.api.bean.ApiLoginResponse;
+import com.supwisdom.mutlitenant.client.annotations.JwtMethod;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -25,5 +26,6 @@
                                      @PathVariable(value = "clientid") String clientid);
 
   @RequestMapping(value = "/api/auth/refresh", method = RequestMethod.GET)
+  @JwtMethod
   ApiLoginResponse refresh();
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java
index d68a238..ee873d9 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java
@@ -3,6 +3,7 @@
 import com.supwisdom.dlpay.api.bean.CitizenCardPayfinishParam;
 import com.supwisdom.dlpay.api.bean.CitizenCardPayinitParam;
 import com.supwisdom.dlpay.api.bean.CitizenPayResponse;
+import com.supwisdom.mutlitenant.client.annotations.JwtMethod;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -13,8 +14,10 @@
 @FeignClient(value = "citizenCardPay", url = "${payapi.url}")
 public interface CitizenCardPayProxy {
   @RequestMapping(value = "/api/consume/citizencard/payinit", method = RequestMethod.GET)
+  @JwtMethod
   CitizenPayResponse citizencardPayinit(@RequestBody CitizenCardPayinitParam param);
 
   @RequestMapping(value = "/api/consume/citizencard/payfinish", method = RequestMethod.GET)
+  @JwtMethod
   CitizenPayResponse citizencardPayFinish(@RequestBody CitizenCardPayfinishParam param);
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ConsumePropxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ConsumePropxy.java
index 62584f7..dc287f3 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ConsumePropxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ConsumePropxy.java
@@ -1,6 +1,7 @@
 package com.supwisdom.dlpay.paysdk.proxy;
 
 import com.supwisdom.dlpay.api.bean.*;
+import com.supwisdom.mutlitenant.client.annotations.JwtMethod;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -11,17 +12,22 @@
 public interface ConsumePropxy {
 
     @PostMapping("/qrcode/init")
+    @JwtMethod
     QrcodePayResponse qrcodePayInit(@RequestBody QrcodePayParam param);
 
     @PostMapping("/qrcode/confirm")
+    @JwtMethod
     QrcodePayResponse  qrcodePayConfirm(@RequestBody QrcodePayParam param);
 
     @PostMapping("/thirdpay/init")
+    @JwtMethod
     ThirdPayResponse thirdpayInit(@RequestBody ThirdPayinitParam param);
 
     @PostMapping("/thirdpay/finish")
+    @JwtMethod
     ThirdPayResponse thirdpayFinish(@RequestBody ThirdPayfinishParam param);
 
     @PostMapping("/qrcodequery")
+    @JwtMethod
     DoorQrcodeResponse qrcodequery(@RequestBody DoorQRCodeParam param);
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ShopProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ShopProxy.java
index 4562fa2..87f20e9 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ShopProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/ShopProxy.java
@@ -4,6 +4,7 @@
 import com.supwisdom.dlpay.api.bean.OpenShopParam;
 import com.supwisdom.dlpay.api.bean.QueryShopParam;
 import com.supwisdom.dlpay.api.bean.ShopResponse;
+import com.supwisdom.mutlitenant.client.annotations.JwtMethod;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -14,11 +15,14 @@
 @RequestMapping("/api/shop")
 public interface ShopProxy {
   @PostMapping("/open")
+  @JwtMethod
   ShopResponse openAccount(@RequestBody OpenShopParam param);
 
   @GetMapping("/query")
+  @JwtMethod
   ShopResponse queryShop(@RequestBody QueryShopParam param);
 
   @PostMapping("/downloadshopbill")
+  @JwtMethod
   String downloadShopBill(@RequestBody DownloadShopBillParam param);
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/TransactionProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/TransactionProxy.java
index 712fcd3..087936e 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/TransactionProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/TransactionProxy.java
@@ -1,6 +1,7 @@
 package com.supwisdom.dlpay.paysdk.proxy;
 
 import com.supwisdom.dlpay.api.bean.*;
+import com.supwisdom.mutlitenant.client.annotations.JwtMethod;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -8,17 +9,22 @@
 @FeignClient(name = "payTransactionProxy", url = "${payapi.url}")
 public interface TransactionProxy {
   @PostMapping("/api/consume/paycancel")
+  @JwtMethod
   PayReverseResponse payCancel(@RequestBody ConsumePayCancelParam param);
 
   @PostMapping("/api/consume/payrefund")
+  @JwtMethod
   PayReverseResponse payRefund(@RequestBody ConsumePayRefundParam param);
 
   @PostMapping("/api/consume/queryresult")
+  @JwtMethod
   QueryTransDtlResponse queryDtlResult(@RequestBody QueryDtlResultParam param);
 
   @PostMapping("/api/deposit/merchant/init")
+  @JwtMethod
   MerchantDepositResponse depositInit(@RequestBody MerchantDepositParam param);
 
   @PostMapping("/api/deposit/merchant/confirm")
+  @JwtMethod
   MerchantDepositResponse depositConfirm(@RequestBody MerchantDepositParam param);
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/UserProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/UserProxy.java
index 7a17aec..7ba2336 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/UserProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/UserProxy.java
@@ -1,41 +1,53 @@
 package com.supwisdom.dlpay.paysdk.proxy;
 
 import com.supwisdom.dlpay.api.bean.*;
+import com.supwisdom.mutlitenant.client.annotations.JwtMethod;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.*;
 
 @FeignClient(value = "userProxy", url = "${payapi.url}")
 public interface UserProxy {
   @PostMapping("/api/user/open")
+  @JwtMethod
   UserResponse openAccount(@RequestBody OpenUserParam param);
 
   @PostMapping("/api/user/query")
+  @JwtMethod
   UserResponse queryAccount(@RequestBody QueryUserParam param);
 
   @PostMapping("/api/user/modify")
+  @JwtMethod
   UserResponse modifyAccount(@RequestBody ModifyUserParam param);
 
   @PostMapping("/api/user/querybycardno")
+  @JwtMethod
   UserInforResponse querybycardno(@RequestBody QueryUserParam param);
 
   @PostMapping("/api/user/querycards")
+  @JwtMethod
   CardsResponse querycards(@RequestBody QueryCardsParam param);
 
   @PostMapping("/api/user/testmsg")
+  @JwtMethod
   ApiResponse testmsg();
 
   @PostMapping("/api/user/biz_init")
+  @JwtMethod
   CardBizResponse bizInit(@RequestBody CardBizParam param);
 
   @PostMapping("/api/user/biz_confirm")
+  @JwtMethod
   CardBizResponse bizConfirm(@RequestBody CardBizParam param);
 
   @PostMapping("/api/user/biz_refund_init")
+  @JwtMethod
   CardBizResponse bizRefundInit(@RequestBody CardBizRefundParam param);
 
   @PostMapping("/api/user/biz_refund")
+  @JwtMethod
   CardBizResponse bizRefund(String refno);
 
   @RequestMapping(value = "/api/user/biz_query", method = RequestMethod.GET)
+  @JwtMethod
   CardBizResponse bizQuery(@RequestParam("refno") String refno);
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/YktPayProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/YktPayProxy.java
index 46d967c..fa44fc8 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/YktPayProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/YktPayProxy.java
@@ -2,6 +2,7 @@
 
 import com.supwisdom.dlpay.api.bean.CitizenCardPayfinishParam;
 import com.supwisdom.dlpay.api.bean.YktCardPayinitParam;
+import com.supwisdom.mutlitenant.client.annotations.JwtMethod;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -12,8 +13,10 @@
 @FeignClient(name = "yktPayProxy", url = "${payapi.url}")
 public interface YktPayProxy {
   @PostMapping("/api/consume/ykt/payinit")
+  @JwtMethod
   ResponseEntity<Map<String, String>> yktPayInit(@RequestBody YktCardPayinitParam param);
 
   @PostMapping("/api/consume/ykt/payfinish")
+  @JwtMethod
   ResponseEntity<Map<String, String>> yktPayFinish(@RequestBody CitizenCardPayfinishParam param);
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/DefaultMultiTenantProvider.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/DefaultMultiTenantProvider.java
deleted file mode 100644
index 95dd221..0000000
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/DefaultMultiTenantProvider.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.supwisdom.dlpay.paysdk.tenant;
-
-public class DefaultMultiTenantProvider implements MultiTenantProvider {
-  @Override
-  public String getCurrentTenant() {
-    return "{tenantid}";
-  }
-}
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/DefaultMultiTenantProviderFactory.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/DefaultMultiTenantProviderFactory.java
deleted file mode 100644
index 0b42fa3..0000000
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/DefaultMultiTenantProviderFactory.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.supwisdom.dlpay.paysdk.tenant;
-
-public class DefaultMultiTenantProviderFactory implements MultiTenantProviderFactory {
-  private MultiTenantProvider provider = new DefaultMultiTenantProvider();
-
-  public MultiTenantProvider getProvider() {
-    return provider;
-  }
-}
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/MultiTenantProvider.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/MultiTenantProvider.java
deleted file mode 100644
index 5db786c..0000000
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/MultiTenantProvider.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.supwisdom.dlpay.paysdk.tenant;
-
-public interface MultiTenantProvider {
-  String getCurrentTenant();
-}
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/MultiTenantProviderFactory.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/MultiTenantProviderFactory.java
deleted file mode 100644
index bc137c7..0000000
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/tenant/MultiTenantProviderFactory.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.supwisdom.dlpay.paysdk.tenant;
-
-public interface MultiTenantProviderFactory {
-  MultiTenantProvider getProvider();
-}
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/Constants.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/Constants.java
index f3dae03..1384897 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/Constants.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/Constants.java
@@ -3,4 +3,5 @@
 public class Constants {
   public static final String HEADER_TENANT_ID = "X-TENANT-ID";
   public static final String JWT_HEADER = "Authorization";
+  public static final String JWT_SCHEMA = "Bearer";
 }
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/JwtContext.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/JwtContext.java
deleted file mode 100644
index 0bd07ef..0000000
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/JwtContext.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.supwisdom.dlpay.paysdk.utils;
-
-public class JwtContext {
-  private static String jwt;
-
-  public static String getJwt() {
-    synchronized (JwtContext.class) {
-      return jwt;
-    }
-  }
-
-  public static void setJwt(String j) {
-    synchronized (JwtContext.class) {
-      jwt = j;
-    }
-  }
-}
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/Utils.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/Utils.java
deleted file mode 100644
index 27b15a0..0000000
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/utils/Utils.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.supwisdom.dlpay.paysdk.utils;
-
-public class Utils {
-
-}
diff --git a/payapi-sdk/src/main/resources/META-INF/spring.factories b/payapi-sdk/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..91aa77c
--- /dev/null
+++ b/payapi-sdk/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+  com.supwisdom.dlpay.paysdk.PayAPISDKConfigure
\ No newline at end of file
diff --git a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/APITestConfig.java b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/APITestConfig.java
new file mode 100644
index 0000000..f8d2605
--- /dev/null
+++ b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/APITestConfig.java
@@ -0,0 +1,12 @@
+package com.supwisdom.dlpay.paysdktest;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class APITestConfig {
+  @Bean
+  public TestJwtClientConfigure testJwtClientConfigure() {
+    return new TestJwtClientConfigure();
+  }
+}
diff --git a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java
index 231a684..7d47710 100644
--- a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java
+++ b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java
@@ -5,6 +5,8 @@
 import com.supwisdom.dlpay.api.util.DateUtil;
 import com.supwisdom.dlpay.paysdk.ApiLoginHelper;
 import com.supwisdom.dlpay.paysdk.proxy.*;
+import com.supwisdom.mutlitenant.client.annotations.EnableTenantJwtClient;
+import com.supwisdom.mutlitenant.client.config.JwtTenantAuthentication;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,8 +33,9 @@
     classes = CitizenCardPayProxyTest.class)
 @ImportAutoConfiguration({RibbonAutoConfiguration.class,
     FeignRibbonClientAutoConfiguration.class, FeignAutoConfiguration.class,
-    HttpMessageConvertersAutoConfiguration.class})
+    HttpMessageConvertersAutoConfiguration.class, APITestConfig.class})
 @EnableFeignClients(basePackages = "com.supwisdom.dlpay.paysdk")
+@EnableTenantJwtClient
 @ComponentScan(basePackages = {"com.supwisdom.dlpay.paysdk"})
 public class CitizenCardPayProxyTest {
   private final static String appid = "700001";
@@ -40,6 +43,9 @@
 
   private final static String operid = "1001";
 
+  public final static JwtTenantAuthentication authentication = new JwtTenantAuthentication(appid, secret,
+      "{tenantid}");
+
   @Autowired
   private ApiLoginProxy apiLoginProxy;
 
@@ -58,9 +64,6 @@
 
   @org.junit.Test
   public void citizencardPayinit() {
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
-
     ApiVersionResponse version = apiCommonProxy.apiVersion();
 
     assertThat("get version error " + version.getException(),
@@ -83,8 +86,6 @@
   @Test
   public void openShopAccount() {
 
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
     ApiVersionResponse version = apiCommonProxy.apiVersion();
 
     assertThat("get version error " + version.getException(),
@@ -104,8 +105,6 @@
   @Test
   public void openUserAccount() {
 
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
     ApiVersionResponse version = apiCommonProxy.apiVersion();
 
     assertThat("get version error " + version.getException(),
@@ -125,8 +124,7 @@
 
   @Test
   public void qrcodeInit() {
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
+
     ApiVersionResponse version = apiCommonProxy.apiVersion();
 
     assertThat("get version error " + version.getException(),
@@ -149,8 +147,6 @@
 
   @Test
   public void qrcodePay() {
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
     ApiVersionResponse version = apiCommonProxy.apiVersion();
 
     assertThat("get version error " + version.getException(),
@@ -180,8 +176,6 @@
 
   @Test
   public void qrcodeQuery() {
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
     DoorQRCodeParam param = new DoorQRCodeParam();
     param.setQrcode("6M4I1KGUO_UOVJVYCW52FQ");
 
@@ -204,8 +198,6 @@
 
   @Test
   public void testmsg() {
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
     ApiResponse response = userProxy.testmsg();
     assertThat("test msg " + response.getRetmsg() + response.getException(),
         response.getRetcode(), equalTo(0));
@@ -213,8 +205,7 @@
 
   @Test
   public void queryCards() {
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
+
     QueryCardsParam param = new QueryCardsParam();
     param.setStarttime("20190724100001");
     param.setEndtime("20190826100001");
@@ -231,8 +222,6 @@
 
   @Test
   public void testPublishCard() {
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
 
     CardBizParam param = new CardBizParam();
     param.setTransdate(DateUtil.getNow("yyyyMMdd"));
diff --git a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/MultiTenantProxyTest.java b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/MultiTenantProxyTest.java
deleted file mode 100644
index 45b1b4c..0000000
--- a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/MultiTenantProxyTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.supwisdom.dlpay.paysdktest;
-
-import com.supwisdom.dlpay.paysdk.ApiLoginHelper;
-import com.supwisdom.dlpay.paysdk.proxy.ApiLoginProxy;
-import com.supwisdom.dlpay.paysdk.tenant.MultiTenantProvider;
-import com.supwisdom.dlpay.paysdk.tenant.MultiTenantProviderFactory;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
-import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.context.TestConfiguration;
-import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
-import org.springframework.cloud.openfeign.EnableFeignClients;
-import org.springframework.cloud.openfeign.FeignAutoConfiguration;
-import org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Primary;
-import org.springframework.test.context.junit4.SpringRunner;
-
-@RunWith(SpringRunner.class)
-//@SpringBootTest(properties = {
-//    "payapi.url=http://localhost:8080/payapi"},
-//    classes = MultiTenantProxyTest.class)
-@ImportAutoConfiguration({RibbonAutoConfiguration.class,
-    FeignRibbonClientAutoConfiguration.class, FeignAutoConfiguration.class,
-    HttpMessageConvertersAutoConfiguration.class})
-@EnableFeignClients(basePackages = "com.supwisdom.dlpay.paysdk")
-@ComponentScan(basePackages = {"com.supwisdom.dlpay.paysdk"})
-public class MultiTenantProxyTest {
-
-  @Autowired
-  private ApiLoginProxy apiLoginProxy;
-
-  private final static String appid = "700001";
-  private final static String secret = "d6dd7f0d4551419d8d11736d0f28df0d";
-
-
-  @TestConfiguration
-  static class MultiTenantTestBean {
-    @Bean
-    @Primary
-    public MultiTenantProviderFactory newProviderFactory() {
-      return () -> (MultiTenantProvider) () -> "122020";
-    }
-  }
-
-
-  @Test
-  public void testMultiTenant() {
-    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-    helper.login(appid, secret);
-  }
-}
diff --git a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/TestJwtClientConfigure.java b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/TestJwtClientConfigure.java
new file mode 100644
index 0000000..15c2c2b
--- /dev/null
+++ b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/TestJwtClientConfigure.java
@@ -0,0 +1,11 @@
+package com.supwisdom.dlpay.paysdktest;
+
+import com.supwisdom.mutlitenant.client.JwtClientConfigure;
+import com.supwisdom.mutlitenant.client.JwtClientConfigureAdapter;
+
+public class TestJwtClientConfigure implements JwtClientConfigureAdapter {
+  @Override
+  public void configure(JwtClientConfigure configure) {
+    configure.withAuthenication(CitizenCardPayProxyTest.authentication);
+  }
+}
diff --git a/payapi/Dockerfile b/payapi/Dockerfile
index 28f3e81..6975293 100644
--- a/payapi/Dockerfile
+++ b/payapi/Dockerfile
@@ -1,9 +1,13 @@
 FROM openjdk:8
 
-COPY payapi-1.jar /opt/payapi/payapi.jar
+ARG BUILD_VERSION
+
+ENV EXEC_JAR=payapi-$BUILD_VERSION.jar
+
+COPY payapi-${BUILD_VERSION}.jar /opt/payapi/
 
 EXPOSE 8080
 
 WORKDIR /opt/payapi
 
-CMD ["java" , "-jar", "payapi.jar"]
+CMD java -jar ${EXEC_JAR}
diff --git a/payapi/build.gradle b/payapi/build.gradle
index 9dcd2e4..d8f169c 100644
--- a/payapi/build.gradle
+++ b/payapi/build.gradle
@@ -14,14 +14,15 @@
 
 println("Build version: $buildVersion")
 
+
 bootJar {
     enabled = true
     mainClassName = payapiStartClass
-    def standalone = ""
-    if (rootProject.hasProperty("no-multi-tenant")) {
-        standalone = "-stangalone-"
-    }
-    archiveFileName = "${project.name}${standalone}-${buildVersion}.${archiveExtension.getOrElse('.jar')}"
+//    def standalone = ""
+//    if (rootProject.hasProperty("no-multi-tenant")) {
+//        standalone = "-stangalone-"
+//
+    archiveFileName = "${project.name}-${buildVersion}.${archiveExtension.getOrElse('.jar')}"
     manifest {
         attributes("Payapi-Version": buildVersion,
                 "Payapi-Buildtime": buildTime)
@@ -51,12 +52,11 @@
     }
     println("Docker image tag : ${imageVersion}")
     name "${dockerRegistry}/payapi:${imageVersion}"
-    println(jar.archiveFile.get())
-    files jar.archiveFile.get()
+    println(bootJar.archiveFile.get())
+    files bootJar.archiveFile.get()
+    buildArgs([BUILD_VERSION: "${buildVersion}"])
 }
 
-docker.dependsOn(jar)
-
 configurations {
     developmentOnly
     runtimeClasspath {
@@ -107,6 +107,7 @@
 
     implementation "com.supwisdom:multi-tenant-core:${multiTenantLibVersion}"
     implementation "com.supwisdom:multi-tenant-datasource:${multiTenantLibVersion}"
+    implementation "com.supwisdom:multi-tenant-jwt:${multiTenantLibVersion}"
 
     implementation "org.bitbucket.b_c:jose4j:${jose4jVersion}"
     implementation files("libs/masmgc.sdk.sms-0.0.1-SNAPSHOT.jar")
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/core/JwtConfig.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/core/JwtConfig.java
deleted file mode 100644
index 85167fd..0000000
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/core/JwtConfig.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.supwisdom.dlpay.framework.core;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class JwtConfig {
-  @Value("${jwt.secret}")
-  private String secret;
-  @Value("${jwt.expiration:3600}")
-  private Long expiration = 3600L;
-  @Value("${jwt.header:Authorization}")
-  private String header = "Authorization";
-  @Value("${jwt.token_header:Bearer }")
-  private String tokenHeader = "Bearer ";
-
-  @Value("${jwt.multitenant:false}")
-  private Boolean multiTenant = false;
-
-  public String getSecret() {
-    return secret;
-  }
-
-  public Long getExpiration() {
-    return expiration;
-  }
-
-  public String getHeader() {
-    return header;
-  }
-
-  public String getTokenHeader() {
-    return tokenHeader;
-  }
-
-  public void setExpiration(Long expiration) {
-    this.expiration = expiration;
-  }
-
-  public Boolean getMultiTenant() {
-    return multiTenant;
-  }
-
-  public void setMultiTenant(Boolean multiTenant) {
-    this.multiTenant = multiTenant;
-  }
-}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/core/JwtToken.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/core/JwtToken.java
deleted file mode 100644
index 072ea5d..0000000
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/core/JwtToken.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.supwisdom.dlpay.framework.core;
-
-import org.jose4j.jwt.NumericDate;
-
-public class JwtToken {
-  private String jti;
-  private NumericDate expiration;
-  private String jwtToken;
-
-  public JwtToken(String jti, String jwtToken, NumericDate exp) {
-    this.jti = jti;
-    this.jwtToken = jwtToken;
-    this.expiration = exp;
-  }
-
-  public String getJti() {
-    return jti;
-  }
-
-  public void setJti(String jti) {
-    this.jti = jti;
-  }
-
-  public String getJwtToken() {
-    return jwtToken;
-  }
-
-  public void setJwtToken(String jwtToken) {
-    this.jwtToken = jwtToken;
-  }
-
-  public NumericDate getExpiration() {
-    return expiration;
-  }
-
-  public void setExpiration(NumericDate expiration) {
-    this.expiration = expiration;
-  }
-}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/core/JwtTokenUtil.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/core/JwtTokenUtil.java
deleted file mode 100644
index 71f65bf..0000000
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/core/JwtTokenUtil.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.supwisdom.dlpay.framework.core;
-
-import com.supwisdom.dlpay.framework.util.Constants;
-import org.jose4j.jwa.AlgorithmConstraints;
-import org.jose4j.jwk.JsonWebKey;
-import org.jose4j.jws.AlgorithmIdentifiers;
-import org.jose4j.jws.JsonWebSignature;
-import org.jose4j.jwt.JwtClaims;
-import org.jose4j.jwt.MalformedClaimException;
-import org.jose4j.jwt.consumer.InvalidJwtException;
-import org.jose4j.jwt.consumer.JwtConsumer;
-import org.jose4j.jwt.consumer.JwtConsumerBuilder;
-import org.jose4j.lang.JoseException;
-import org.springframework.security.core.userdetails.UserDetails;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class JwtTokenUtil {
-  private JwtConfig jwtConfig;
-
-  public JwtTokenUtil(JwtConfig config) {
-    this.jwtConfig = config;
-  }
-
-  public String getHeader() {
-    return jwtConfig.getHeader();
-  }
-
-  public JwtToken generateToken(Map<String, Object> params) throws JoseException, MalformedClaimException {
-    JwtClaims claims = new JwtClaims();
-    claims.setIssuer(params.get("issuer").toString());  // who creates the token and signs it
-    if (params.get("audience") != null) {
-      claims.setAudience(params.get("audience").toString());
-    }
-    claims.setExpirationTimeMinutesInTheFuture(jwtConfig.getExpiration() / 60); // time when the token will expire (10 minutes from now)
-    claims.setGeneratedJwtId();
-    claims.setIssuedAtToNow();  // when the token was issued/created (now)
-    claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago)
-    if (params.get("subject") != null) {
-      claims.setSubject(params.get("subject").toString()); // the subject/principal is whom the token is about
-    }
-    if (params.get(Constants.JWT_CLAIM_AUTHORITIES) != null) {
-      claims.setClaim(Constants.JWT_CLAIM_AUTHORITIES, params.get(Constants.JWT_CLAIM_AUTHORITIES));
-    }
-    if (params.get(Constants.JWT_CLAIM_UID) != null) {
-      claims.setClaim(Constants.JWT_CLAIM_UID, params.get(Constants.JWT_CLAIM_UID));
-    }
-    if (params.get(Constants.JWT_CLAIM_TENANTID) != null) {
-      claims.setClaim(Constants.JWT_CLAIM_TENANTID, params.get(Constants.JWT_CLAIM_TENANTID));
-    }
-    /*
-    claims.setClaim("email", "mail@example.com"); // additional claims/attributes about the subject can be added
-    List<String> groups = Arrays.asList("group-one", "other-group", "group-three");
-    claims.setStringListClaim("groups", groups); // multi-valued claims work too and will end up as a JSON array
-     */
-
-    Map<String, Object> keySpec = new HashMap<>();
-    keySpec.put("kty", "oct");
-    keySpec.put("k", jwtConfig.getSecret());
-    JsonWebKey key = JsonWebKey.Factory.newJwk(keySpec);
-    JsonWebSignature jws = new JsonWebSignature();
-    jws.setPayload(claims.toJson());
-    jws.setKey(key.getKey());
-    jws.setKeyIdHeaderValue(key.getKeyId());
-    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);
-    return new JwtToken(claims.getJwtId(), jws.getCompactSerialization(), claims.getExpirationTime());
-  }
-
-  public JwtToken generateToken(UserDetails userDetails) throws JoseException, MalformedClaimException {
-    Map<String, Object> claims = new HashMap<>();
-    claims.put("uid", userDetails.getUsername());
-    return generateToken(claims);
-  }
-
-  public Map<String, Object> verifyToken(String token) throws JoseException, InvalidJwtException {
-    Map<String, Object> keySpec = new HashMap<>();
-    keySpec.put("kty", "oct");
-    keySpec.put("k", jwtConfig.getSecret());
-    JsonWebKey key = JsonWebKey.Factory.newJwk(keySpec);
-    JwtConsumer jwtConsumer = new JwtConsumerBuilder()
-        .setRequireExpirationTime() // the JWT must have an expiration time
-        .setAllowedClockSkewInSeconds(30) // allow some leeway in validating time based claims to account for clock skew
-        .setVerificationKey(key.getKey()) // verify the signature with the public key
-        .setSkipDefaultAudienceValidation()
-        .setJwsAlgorithmConstraints( // only allow the expected signature algorithm(s) in the given context
-            new AlgorithmConstraints(org.jose4j.jwa.AlgorithmConstraints.ConstraintType.WHITELIST, // which is only RS256 here
-                AlgorithmIdentifiers.HMAC_SHA256))
-        .build(); // create the JwtConsumer instance
-
-    //  Validate the JWT and process it to the Claims
-    JwtClaims jwtClaims = jwtConsumer.processToClaims(token);
-    return jwtClaims.getClaimsMap();
-  }
-}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/JwtRedis.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/JwtRedis.java
deleted file mode 100644
index d32ff8e..0000000
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/JwtRedis.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.supwisdom.dlpay.framework.domain;
-
-import org.springframework.data.annotation.Id;
-import org.springframework.data.redis.core.RedisHash;
-import org.springframework.data.redis.core.TimeToLive;
-
-
-@RedisHash(value = "api_jwt")
-public class JwtRedis {
-  @Id
-  String jti;
-
-  String status;
-
-  String uid;
-
-  @TimeToLive
-  Long expiration;
-
-  public String getJti() {
-    return jti;
-  }
-
-  public void setJti(String jti) {
-    this.jti = jti;
-  }
-
-  public String getStatus() {
-    return status;
-  }
-
-  public void setStatus(String status) {
-    this.status = status;
-  }
-
-  public Long getExpiration() {
-    return expiration;
-  }
-
-  public void setExpiration(Long expiration) {
-    this.expiration = expiration;
-  }
-
-  public String getUid() {
-    return uid;
-  }
-
-  public void setUid(String uid) {
-    this.uid = uid;
-  }
-}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TTenantUserDB.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TTenantUserDB.java
index 7df05a7..6f3258f 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TTenantUserDB.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TTenantUserDB.java
@@ -2,13 +2,14 @@
 
 import javax.persistence.*;
 import javax.validation.constraints.NotNull;
+import java.io.Serializable;
 
 @Entity
 @Table(name = "t_tenant_user_db", schema = "public",
     indexes = {@Index(name = "tenant_db_dbid_idx", columnList = "dbid"),
         @Index(name = "tenant_db_schema_idx", columnList = "schema"),
         @Index(name = "tenant_db_idx2", columnList = "dbid, schema", unique = true)})
-public class TTenantUserDB {
+public class TTenantUserDB implements Serializable {
   @Id
   @Column(name = "id", length = 32)
   private String id;
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/redisrepo/ApiJwtRepository.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/redisrepo/ApiJwtRepository.java
deleted file mode 100644
index 3371b31..0000000
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/redisrepo/ApiJwtRepository.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.supwisdom.dlpay.framework.redisrepo;
-
-import com.supwisdom.dlpay.framework.domain.JwtRedis;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.stereotype.Repository;
-
-public interface ApiJwtRepository extends CrudRepository<JwtRedis, String> {
-}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantUserAdapter.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantUserAdapter.java
index fddcfd7..1a0a92b 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantUserAdapter.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantUserAdapter.java
@@ -5,6 +5,7 @@
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
 import org.springframework.context.annotation.Primary;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.stereotype.Component;
 
@@ -17,10 +18,13 @@
 public class MultiTenantUserAdapter implements AbstractTenantUserOperator {
   private static final String DOMAIN_SEP = "@";
 
-  private TenantSessionHelper tenantSessionHelper;
+  private final TenantSessionHelper tenantSessionHelper;
 
-  public MultiTenantUserAdapter(TenantSessionHelper tenantSessionHelper) {
+  private final RedisTemplate<String, String> redisTemplate;
+
+  public MultiTenantUserAdapter(TenantSessionHelper tenantSessionHelper, RedisTemplate<String, String> redisTemplate) {
     this.tenantSessionHelper = tenantSessionHelper;
+    this.redisTemplate = redisTemplate;
   }
 
   @Override
@@ -30,7 +34,15 @@
     if (StringUtils.isEmpty(domain)) {
       tenantSessionHelper.setSessionTenantById(Constants.DEFAULT_TENANTID);
     } else {
-      tenantSessionHelper.setSessionTenantById(domain);
+      String schema = redisTemplate.opsForValue().get(domain);
+      if (StringUtils.isEmpty(schema)) {
+        schema = "public";
+      }
+      String tenantId = redisTemplate.opsForValue().get(schema);
+      if (StringUtils.isEmpty(schema)) {
+        tenantId = "default";
+      }
+      tenantSessionHelper.setSessionTenantById(tenantId);
     }
     if (StringUtils.isEmpty(realname)) {
       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 4b88ed0..4cd2abe 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt
@@ -3,15 +3,21 @@
 import com.supwisdom.dlpay.framework.service.TenantService
 import com.supwisdom.dlpay.framework.tenant.TenantCacheKeyGen
 import com.supwisdom.dlpay.framework.util.Constants
+import com.supwisdom.multitenant.TenantContextHolder
 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 com.supwisdom.multitenant.exceptions.TenantNotDefException
+import com.supwisdom.multitenant.jwt.JwtTenantConfigAdapter
+import com.supwisdom.multitenant.jwt.annotations.EnableJwtTenantInterceptor
+import com.supwisdom.multitenant.jwt.config.JwtTenantConfig
+import com.supwisdom.multitenant.jwt.config.JwtToken
 import io.lettuce.core.ReadFrom
 import mu.KotlinLogging
 import net.javacrumbs.shedlock.core.LockProvider
 import net.javacrumbs.shedlock.provider.redis.spring.RedisLockProvider
+import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.beans.factory.annotation.Value
 import org.springframework.boot.SpringApplication
@@ -37,6 +43,7 @@
 import org.springframework.data.redis.core.RedisTemplate
 import org.springframework.data.redis.repository.configuration.EnableRedisRepositories
 import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer
 import org.springframework.data.redis.serializer.StringRedisSerializer
 import org.springframework.http.client.SimpleClientHttpRequestFactory
 import org.springframework.scheduling.annotation.EnableScheduling
@@ -72,6 +79,15 @@
     }
 
     @Bean
+    fun redisTempalte(factor: RedisConnectionFactory): RedisTemplate<String, JwtToken> {
+        val template = RedisTemplate<String, JwtToken>();
+        template.setConnectionFactory(factor)
+        template.keySerializer = StringRedisSerializer()
+        template.valueSerializer = Jackson2JsonRedisSerializer(JwtToken::class.java)
+        return template
+    }
+
+    @Bean
     fun lockProvider(connectionFactory: RedisConnectionFactory): LockProvider {
         return RedisLockProvider(connectionFactory, "prod")
     }
@@ -156,6 +172,8 @@
     fun restTemplate(factory: SimpleClientHttpRequestFactory): RestTemplate {
         return RestTemplate(factory)
     }
+
+
 }
 
 
@@ -172,34 +190,58 @@
 class MyTenantDetailsProvider : TenantDetailsProvider {
     @Autowired
     private lateinit var tenantService: TenantService
+    @Autowired
+    private lateinit var redisTemplate: RedisTemplate<String, String>
+
+    private val logger = KotlinLogging.logger { }
 
     private val defaultTenant = TenantDetails().apply {
         id = Constants.DEFAULT_TENANTID
         dbSchema = "public"
         dataCenter = "default"
+        enabled = true
     }
 
     override fun defaultTenant(): TenantDetails {
         return defaultTenant
     }
 
-    override fun createDetailsById(id: String?): TenantDetails {
-        return tenantService.findByTenantId(id)?.let { catalog ->
-            TenantDetails().apply {
-                this.id = catalog.id
-                dbSchema = catalog.schema
-                dataCenter = "default"
-            }
-        } ?: return defaultTenant
+    override fun createDetailsById(id: String): TenantDetails {
+        logger.debug { "find tenant id <$id> ..." }
+        val schema = redisTemplate.opsForValue().get(id) ?: return defaultTenant
+        return TenantDetails().apply {
+            this.id = id
+            dbSchema = schema
+            dataCenter = "default"
+            enabled = true
+        }
+    }
+}
+
+@Component
+class MyTenantJwtConfigAdapter : JwtTenantConfigAdapter {
+    @Value("\${jwt.secret}")
+    private lateinit var jwtSecret: String;
+
+    override fun getConfig(): JwtTenantConfig {
+        if (TenantContextHolder.getContext().tenant == null) {
+            throw TenantNotDefException("未定义Tenant id")
+        }
+        return JwtTenantConfig().apply {
+            this.tenantId = TenantContextHolder.getContext().tenant.id
+            this.secret = jwtSecret
+        }
     }
 }
 
 @SpringBootApplication
 @EnableDiscoveryClient
 @EnableScheduling
+@EnableSchedulerLock(defaultLockAtMostFor = "PT15m")
 @EnableCaching
 @EnableHttpHeaderTenantInterceptor
 @EnableSessionTenantInterceptor
+@EnableJwtTenantInterceptor
 @ServletComponentScan
 class PayApiApplication : SpringBootServletInitializer() {
 
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 deabb41..22c1490 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
@@ -5,21 +5,20 @@
 import com.supwisdom.dlpay.api.bean.ApiLoginResponse
 import com.supwisdom.dlpay.exception.TransactionCheckException
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
-import com.supwisdom.dlpay.framework.core.JwtConfig
-import com.supwisdom.dlpay.framework.core.JwtTokenUtil
 import com.supwisdom.dlpay.framework.dao.ApiClientDao
 import com.supwisdom.dlpay.framework.dao.TenantConfigDao
 import com.supwisdom.dlpay.framework.domain.ApiClientRedis
-import com.supwisdom.dlpay.framework.domain.JwtRedis
 import com.supwisdom.dlpay.framework.domain.TOperator
 import com.supwisdom.dlpay.framework.redisrepo.ApiClientRepository
-import com.supwisdom.dlpay.framework.redisrepo.ApiJwtRepository
 import com.supwisdom.dlpay.framework.security.validate.ImageCodeUtil
 import com.supwisdom.dlpay.framework.security.validate.VerifyCode
 import com.supwisdom.dlpay.framework.service.CommonService
 import com.supwisdom.dlpay.framework.service.SystemUtilService
 import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.system.service.FunctionService
+import com.supwisdom.multitenant.jwt.JwtRequestData
+import com.supwisdom.multitenant.jwt.JwtTenantService
+import com.supwisdom.multitenant.jwt.JwtTokenBuilder
 import mu.KotlinLogging
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.data.redis.connection.RedisConnectionFactory
@@ -37,7 +36,9 @@
 import org.springframework.web.bind.annotation.*
 import org.springframework.web.context.request.ServletWebRequest
 import java.io.IOException
+import java.time.Instant
 import java.util.*
+import javax.annotation.Resource
 import javax.imageio.ImageIO
 import javax.servlet.http.HttpServletRequest
 import javax.servlet.http.HttpServletResponse
@@ -50,19 +51,19 @@
     lateinit var apiClientRepository: ApiClientRepository
 
     @Autowired
-    lateinit var apiJwtRepository: ApiJwtRepository
-
-    @Autowired
     lateinit var apiClientDao: ApiClientDao
 
     @Autowired
     lateinit var systemUtil: SystemUtilService
 
     @Autowired
-    lateinit var jwtConfig: JwtConfig
+    private lateinit var tetantConfigDao: TenantConfigDao
 
     @Autowired
-    private lateinit var tetantConfigDao: TenantConfigDao
+    private lateinit var jwtTenantService: JwtTenantService
+
+    @Resource(name = "jwtRequestData")
+    private lateinit var jwtRequestData: JwtRequestData
 
     @GetMapping(value = ["/gettoken", "/gettoken/{clientid}"])
     fun loginInit(appid: String, @PathVariable clientid: String?,
@@ -114,24 +115,16 @@
         return apiClientRepository.findById(requestId).let {
             if (it.isPresent && checkSecretToken(it.get(), secret)) {
                 apiClientRepository.deleteById(requestId)
-                val token = JwtTokenUtil(jwtConfig).generateToken(
-                        mapOf(Constants.JWT_CLAIM_UID to appid,
-                                "issuer" to "payapi",
-                                "audience" to (clientid ?: appid),
-                                Constants.JWT_CLAIM_TENANTID to it.get().tenantId,
-                                Constants.JWT_CLAIM_AUTHORITIES to it.get().roles.split(";")))
-                JwtRedis().apply {
-                    jti = token.jti
-                    uid = appid
-                    status = TradeDict.JWT_STATUS_NORMAL
-                    expiration = token.expiration.valueInMillis
-                }.apply {
-                    apiJwtRepository.save(this)
-                }
-
+                val builder = JwtTokenBuilder.create()
+                        .uid(appid)
+                        .issuer("payapi")
+                        .audience(listOf(clientid ?: appid))
+                        .tenantId(it.get().tenantId)
+                        .authorities(it.get().roles.split(";"))
+                val token = jwtTenantService.generate(builder)
                 ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .success(ApiLoginResponse(token.jwtToken,
-                                appid, DateUtil.getUTCTime(token.expiration.valueInMillis))))
+                        .success(ApiLoginResponse(token.get().jwt,
+                                appid, Instant.ofEpochSecond(token.get().expiration).toString())))
             } else {
                 ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
             }
@@ -140,38 +133,29 @@
 
     @GetMapping("/refresh")
     fun refresh(request: HttpServletRequest): ResponseEntity<Any> {
-        val auth = request.getHeader(jwtConfig.header) ?: ""
-        if (!auth.startsWith(jwtConfig.tokenHeader)) {
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
-        }
-        val jwt = JwtTokenUtil(jwtConfig).verifyToken(auth.substring(jwtConfig.tokenHeader.length))
-        val appid = jwt["uid"] as String
-        val result = apiClientDao.findByAppid(appid)?.let {
-            if (it.status == TradeDict.STATUS_NORMAL) {
-                // 新证书
-                val token = JwtTokenUtil(jwtConfig).generateToken(
-                        mapOf(Constants.JWT_CLAIM_UID to appid,
-                                "issuer" to "payapi",
-                                "audience" to jwt["audience"],
-                                Constants.JWT_CLAIM_AUTHORITIES to it.roles.split(";")))
-                JwtRedis().apply {
-                    jti = token.jti
-                    uid = appid
-                    status = TradeDict.JWT_STATUS_NORMAL
-                    expiration = token.expiration.valueInMillis
-                }.apply {
-                    apiJwtRepository.save(this)
-                }
+        val jwt = jwtRequestData.jwtToken
+                ?: return ResponseEntity.ok(ResponseBodyBuilder.create().fail(TradeErrorCode.INPUT_DATA_ERROR,
+                        "jwt unauthorized"))
 
-                ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .success(ApiLoginResponse(token.jwtToken,
-                                appid, DateUtil.getUTCTime(token.expiration.valueInMillis))))
-            } else {
-                ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(mapOf("msg" to "appid error"))
-            }
-        } ?: ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(mapOf("msg" to "appid error"))
-        @Suppress("UNCHECKED_CAST")
-        return result as ResponseEntity<Any>
+        val appid = jwt.uid
+        // 新证书
+        val builder = JwtTokenBuilder.create()
+                .uid(appid)
+                .issuer(jwt.issuer)
+                .audience(jwt.audience)
+                .tenantId(jwt.tenantId)
+                .authorities(jwt.authorities)
+        val token = jwtTenantService.generate(builder)
+
+        return if (token.isPresent) {
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .success(ApiLoginResponse(token.get().jwt,
+                            appid, Instant.ofEpochSecond(token.get().expiration).toString())))
+        } else {
+
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .fail(TradeErrorCode.INPUT_DATA_ERROR, "JWT生成错误"))
+        }
     }
 }
 
@@ -208,25 +192,26 @@
 @RestController
 class UserInforController {
     @Autowired
-    lateinit var jwtConfig: JwtConfig
-    @Autowired
     private lateinit var redisConnectionFactory: RedisConnectionFactory
 
+    @Resource(name = "jwtRequestData")
+    private lateinit var jwtRequestData: JwtRequestData
+
     @RequestMapping("/userinfor")
     fun user(@RequestParam("access_token") access_token: String?,
              @RequestHeader(Constants.HEADER_AUTHORIZATION) auth: String?): ResponseEntity<Any> {
         if (access_token.isNullOrEmpty() && auth.isNullOrEmpty()) {
             return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
         }
-        var jwt: String
-        if(!auth.isNullOrEmpty()){
-            jwt = auth.substring(jwtConfig.tokenHeader.length)
-        }else{
-            jwt = access_token!!
+        val jwt = if (!auth.isNullOrEmpty()) {
+            jwtRequestData.jwtToken.jwt
+        } else {
+            access_token!!
         }
-        val obj: OAuth2Authentication? = RedisTokenStore(redisConnectionFactory).readAuthentication(jwt) ?: return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
+        val obj: OAuth2Authentication? = RedisTokenStore(redisConnectionFactory).readAuthentication(jwt)
+                ?: return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
         val user = obj!!.userAuthentication.principal as UserDetails
-        if(user.username.isNullOrEmpty()){
+        if (user.username.isNullOrEmpty()) {
             return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
         }
         return ResponseEntity.status(HttpStatus.OK).body("""{"name":"${user.username}"}""")
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
index b997a61..e5d2858 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
@@ -2,55 +2,42 @@
 
 import com.jcabi.manifests.Manifests
 import com.supwisdom.dlpay.exception.TransactionProcessException
-import com.supwisdom.dlpay.framework.core.JwtConfig
-import com.supwisdom.dlpay.framework.core.JwtTokenUtil
 import com.supwisdom.dlpay.framework.dao.ApiClientDao
 import com.supwisdom.dlpay.framework.service.CommonService
 import com.supwisdom.dlpay.framework.util.StringUtil
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
+import com.supwisdom.multitenant.jwt.JwtRequestData
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
+import javax.annotation.Resource
 import javax.servlet.http.HttpServletRequest
 
 @Service
 class CommonServiceImpl : CommonService {
     @Autowired
-    lateinit var jwtConfig: JwtConfig
-    @Autowired
     lateinit var apiClientDao: ApiClientDao
 
-    private var jwtUtil: JwtTokenUtil? = null
-
-    private fun getUtil(): JwtTokenUtil {
-        if (jwtUtil == null) {
-            jwtUtil = JwtTokenUtil((jwtConfig))
-        }
-        return jwtUtil as JwtTokenUtil
-    }
+    @Resource(name = "jwtRequestData")
+    private lateinit var jwtRequestData: JwtRequestData
 
     override fun getSystemVersion(): String {
         return try {
-            var ver =  Manifests.read("Payapi-Version") ?: "version 1.0"
+            var ver = Manifests.read("Payapi-Version") ?: "version 1.0"
             ver += Manifests.read("Payapi-Buildtime") ?: "no"
             ver
         } catch (ex: Exception) {
-//            ex.printStackTrace()
             "unknown"
         }
     }
 
     override fun getRequestAppid(request: HttpServletRequest): String {
-        request.getHeader(jwtConfig.header).let {
-            if (null != it && it.startsWith(jwtConfig.tokenHeader)) {
-                val claims = getUtil().verifyToken(it.substring(jwtConfig.tokenHeader.length))
-                val uid = claims["uid"]?.toString()
-                if (!StringUtil.isEmpty(uid)) {
-                    return uid as String
-                }
+        jwtRequestData.jwtToken?.also {
+            val uid = it.uid
+            if (!StringUtil.isEmpty(uid)) {
+                return uid as String
             }
-
-            throw TransactionProcessException(TradeErrorCode.BUSINESS_APPID_NOTFOUND, "APPID未找到") //报错
         }
+        throw TransactionProcessException(TradeErrorCode.BUSINESS_APPID_NOTFOUND, "APPID未找到") //报错
     }
 
     override fun getAppidSecretByRequest(request: HttpServletRequest): String {
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/mobile/AuthLoginHandler.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/mobile/AuthLoginHandler.kt
index c795cbd..6317ab3 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/mobile/AuthLoginHandler.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/mobile/AuthLoginHandler.kt
@@ -3,16 +3,14 @@
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.supwisdom.dlpay.api.bean.JsonResult
 import com.supwisdom.dlpay.api.service.UserService
-import com.supwisdom.dlpay.framework.core.JwtConfig
-import com.supwisdom.dlpay.framework.core.JwtTokenUtil
-import com.supwisdom.dlpay.framework.domain.JwtRedis
-import com.supwisdom.dlpay.framework.redisrepo.ApiJwtRepository
 import com.supwisdom.dlpay.framework.service.SystemUtilService
 import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.mobile.dao.MobileUserDao
 import com.supwisdom.dlpay.mobile.domain.TBMobileUser
 import com.supwisdom.dlpay.mobile.exception.UserLoginFailException
 import com.supwisdom.dlpay.mobile.service.MobileApiService
+import com.supwisdom.multitenant.jwt.JwtTenantService
+import com.supwisdom.multitenant.jwt.JwtTokenBuilder
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.HttpStatus
 import org.springframework.security.authentication.BadCredentialsException
@@ -34,40 +32,30 @@
     @Autowired
     lateinit var objectMapper: ObjectMapper
     @Autowired
-    lateinit var jwtConfig: JwtConfig
-    @Autowired
-    lateinit var apiJwtRepository: ApiJwtRepository
-    @Autowired
     lateinit var systemUtilService: SystemUtilService
     @Autowired
     lateinit var userService: UserService
 
+    @Autowired
+    lateinit var jwtTenantService: JwtTenantService
+
     override fun onAuthenticationSuccess(request: HttpServletRequest, response: HttpServletResponse, authentication: Authentication) {
         val platform = request.getParameter("platform")
         logger.error(platform)
         val temp = authentication.principal as TBMobileUser
         val user = mobileApiService.findUserById(temp.uid)
-        val exp = systemUtilService.getSysparaValueAsInt(SysparaUtil.MOBILE_LOGIN_EXPIRE_IN_SECONDS,60*60*24*3)
-        jwtConfig.expiration = exp.toLong()
+        val exp = systemUtilService.getSysparaValueAsInt(SysparaUtil.MOBILE_LOGIN_EXPIRE_IN_SECONDS, 60 * 60 * 24 * 3)
         if (user != null) {
             //TODO 从数据取jwtConfig.expiration
-            val token = JwtTokenUtil(jwtConfig).generateToken(
-                    mapOf("uid" to user.uid, "issuer" to "payapi",
-                            "audience" to user.loginid,
-                            Constants.JWT_CLAIM_TENANTID to "mobile",
-                            Constants.JWT_CLAIM_AUTHORITIES to temp.authorities))
-            val jwt = JwtRedis().apply {
-                jti = token.jti
-                uid = user.loginid
-                status = TradeDict.JWT_STATUS_NORMAL
-                expiration = token.expiration.valueInMillis
-            }.apply {
-                //删除之前的token
-                if (!user.jti.isNullOrEmpty()) {
-                    apiJwtRepository.deleteById(user.jti!!)
-                }
-                apiJwtRepository.save(this)
-            }
+            val builder = JwtTokenBuilder.create()
+                    .expiration(exp.toLong())
+                    .issuer("payapi")
+                    .uid(user.uid)
+                    .tenantId("mobile")
+                    .authorities(temp.authorities?.toList() ?: listOf<Any>())
+            val token = jwtTenantService.generate(builder)
+
+            val jwt = token.get()
             if (user.loginpwderror > 0) {
                 user.loginpwderror = 0
                 user.loginpwderrortime = null
@@ -77,32 +65,32 @@
             user.jti = jwt.jti
             mobileApiService.saveUser(user)
             var payseted = false
-            if(!user.paypwd.isNullOrEmpty()){
+            if (!user.paypwd.isNullOrEmpty()) {
                 payseted = true
             }
             var name = ""
-            var signed=""
+            var signed = ""
             if (!user.userid.isNullOrEmpty()) {
                 val person = userService.findOnePersonByUserid(user.userid!!)
                 var card = mobileApiService.findCardByUserid(user.userid!!)
                 name = person.name
-                if(card!=null&&card.signed){
+                if (card != null && card.signed) {
                     signed = TradeDict.STATUS_YES
                 }
             }
             response.status = HttpStatus.OK.value()
             response.contentType = "application/json;charset=UTF-8"
             response.writer.write(objectMapper.writeValueAsString(JsonResult.ok()
-                    .put("token", token.jwtToken)
-                    ?.put("expire",token.expiration.valueInMillis)
-                    ?.put("now",System.currentTimeMillis())
+                    .put("token", jwt.jwt)
+                    ?.put("expire", jwt.expiration)
+                    ?.put("now", System.currentTimeMillis())
                     ?.put("tenantid", "mobile")
                     ?.put("name", name)
                     ?.put("uid", user.uid)
                     ?.put("phone", StringUtil.phoneReplace(user.phone))
-                    ?.put("paypwdset",payseted)
+                    ?.put("paypwdset", payseted)
                     ?.put("signed", signed)
-                    ?.put("userid",if(user.userid.isNullOrEmpty()) "" else user.userid)))
+                    ?.put("userid", if (user.userid.isNullOrEmpty()) "" else user.userid)))
         } else {
             throw UserLoginFailException("登录错误")
         }
@@ -128,7 +116,7 @@
             else -> exception.message!!
         }
         val temp = request.getParameter("username")
-        if(!temp.isNullOrEmpty()) {
+        if (!temp.isNullOrEmpty()) {
             mobileUserDao.findByLoginid(temp)?.let {
                 if (it.loginpwderror == 0) {
                     it.loginpwderror = 0
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
index da66271..26289f6 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
@@ -6,10 +6,6 @@
 import com.supwisdom.dlpay.api.service.QRCodeService
 import com.supwisdom.dlpay.api.service.UserService
 import com.supwisdom.dlpay.api.util.MobileNumberCheck
-import com.supwisdom.dlpay.framework.core.JwtConfig
-import com.supwisdom.dlpay.framework.core.JwtTokenUtil
-import com.supwisdom.dlpay.framework.domain.JwtRedis
-import com.supwisdom.dlpay.framework.redisrepo.ApiJwtRepository
 import com.supwisdom.dlpay.framework.service.SystemUtilService
 import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.framework.util.Dictionary
@@ -18,6 +14,9 @@
 import com.supwisdom.dlpay.system.service.DictionaryProxy
 import com.supwisdom.dlpay.util.ConstantUtil
 import com.supwisdom.dlpay.util.RSAKeysGenerate
+import com.supwisdom.multitenant.jwt.JwtRequestData
+import com.supwisdom.multitenant.jwt.JwtTenantService
+import com.supwisdom.multitenant.jwt.JwtTokenBuilder
 import mu.KotlinLogging
 import org.apache.commons.lang.StringUtils
 import org.jose4j.jwt.ReservedClaimNames
@@ -35,6 +34,7 @@
 import org.springframework.web.bind.annotation.RequestParam
 import java.time.Duration
 import java.util.*
+import javax.annotation.Resource
 
 
 @RestController
@@ -45,11 +45,10 @@
     @Autowired
     lateinit var redisTemplate: RedisTemplate<String, String>
     @Autowired
-    lateinit var jwtConfig: JwtConfig
-    @Autowired
-    lateinit var apiJwtRepository: ApiJwtRepository
-    @Autowired
     lateinit var systemUtilService: SystemUtilService
+    @Autowired
+    lateinit var jwtTenantService: JwtTenantService
+
     val logger = KotlinLogging.logger { }
 
     @RequestMapping("/time")
@@ -139,7 +138,7 @@
             }
             user.status = TradeDict.STATUS_NORMAL
             user.registerplatform = platform
-            if(!user.registerplatform.isNullOrEmpty()){
+            if (!user.registerplatform.isNullOrEmpty()) {
                 user.lastloginplatform = user.registerplatform!!.split(",")[1]
             }
             user.devuid = uuid
@@ -181,26 +180,18 @@
         val encoder = BCryptPasswordEncoder()
         user!!.loginpwd = encoder.encode(pwd)
         val exp = systemUtilService.getSysparaValueAsInt(SysparaUtil.MOBILE_LOGIN_EXPIRE_IN_SECONDS, 60 * 60 * 24 * 3)
-        jwtConfig.expiration = exp.toLong()
+//        jwtConfig.expiration = exp.toLong()
         val authorities: Collection<GrantedAuthority> = AuthorityUtils.createAuthorityList("ROLE_USER")
         user.auths = authorities
-        val token = JwtTokenUtil(jwtConfig).generateToken(
-                mapOf("uid" to user.uid, "issuer" to "payapi",
-                        "audience" to user.loginid,
-                        Constants.JWT_CLAIM_TENANTID to "mobile",
-                        Constants.JWT_CLAIM_AUTHORITIES to user.authorities))
-        val jwt = JwtRedis().apply {
-            jti = token.jti
-            uid = user.loginid
-            status = TradeDict.JWT_STATUS_NORMAL
-            expiration = token.expiration.valueInMillis
-        }.apply {
-            //删除之前的token
-            if (!user.jti.isNullOrEmpty()) {
-                apiJwtRepository.deleteById(user.jti!!)
-            }
-            apiJwtRepository.save(this)
-        }
+        val builder = JwtTokenBuilder.create()
+                .expiration(exp.toLong())
+                .uid(user.uid)
+                .issuer("payapi")
+                .tenantId("mobile")
+                .authorities(user.authorities?.toList() ?: listOf<Any>())
+        val token = jwtTenantService.generate(builder)
+        val jwt = token.get()
+
         if (user.loginpwderror > 0) {
             user.loginpwderror = 0
             user.loginpwderrortime = null
@@ -226,9 +217,9 @@
                 signed = TradeDict.STATUS_YES
             }
         }
-        return JsonResult.ok("OK").put("token", token.jwtToken)
+        return JsonResult.ok("OK").put("token", jwt.jwt)
                 ?.put("userid", if (user.userid.isNullOrEmpty()) "" else user.userid)
-                ?.put("expire", token.expiration.valueInMillis)
+                ?.put("expire", jwt.expiration)
                 ?.put("now", System.currentTimeMillis())
                 ?.put("phone", StringUtil.phoneReplace(user.phone))
                 ?.put("paypwdset", payseted)
@@ -252,28 +243,29 @@
     @Autowired
     lateinit var citizencardPayService: CitizencardPayService
     @Autowired
-    lateinit var apiJwtRepository: ApiJwtRepository
+    lateinit var qrcodeService: QRCodeService
     @Autowired
-    lateinit var jwtConfig: JwtConfig
+    lateinit var systemUtilService: SystemUtilService
     @Autowired
-    lateinit var qrcodeService:QRCodeService
+    lateinit var jwtTenantService: JwtTenantService
+
+    @Resource(name = "jwtRequestData")
+    lateinit var jwtRequestData: JwtRequestData
+
     val logger = KotlinLogging.logger { }
 
     @RequestMapping("/idtypes")
     fun idtypes(): JsonResult {
-        var dict = dictionaryProxy.getDictionaryAsMap(Dictionary.IDTYPE)
+        val dict = dictionaryProxy.getDictionaryAsMap(Dictionary.IDTYPE)
         return JsonResult.ok("OK").put("idtypes", dict)!!
     }
 
     @RequestMapping("/logout")
-    fun logout(@RequestHeader("Authorization") auth: String?): ResponseEntity<Any> {
-        if (auth == null) {
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
-        }
-        val jwt = auth.substring(jwtConfig.tokenHeader.length)
-        val claims = JwtTokenUtil(jwtConfig).verifyToken(jwt)
+    fun logout(): ResponseEntity<Any> {
         SecurityContextHolder.clearContext()
-        apiJwtRepository.deleteById(claims[ReservedClaimNames.JWT_ID].toString())
+        jwtRequestData.jwtToken?.also {
+            jwtTenantService.revoke(it)
+        }
         return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
     }
 
@@ -283,42 +275,35 @@
     @RequestMapping("/infor")
     fun getUserInfor(): JsonResult {
         val p = SecurityContextHolder.getContext().authentication
-        var user = mobileApiService.findUserById(p.name)
+        val user = mobileApiService.findUserById(p.name)
                 ?: return JsonResult.error("用户不存在,请注册")
-        var tk= ""
-        if (!user.jti.isNullOrEmpty()) {
-            var opt = apiJwtRepository.findById(user.jti!!)
-            if(opt.isPresent){
-                var jwt =  opt.get()
-                val cur = System.currentTimeMillis()
-                //token 小于12个小时,则更新它
-                if(jwt.expiration-cur<1000*60*60*12){
-                    val token = JwtTokenUtil(jwtConfig).generateToken(
-                            mapOf("uid" to user.uid, "issuer" to "payapi",
-                                    "audience" to user.loginid,
-                                    Constants.JWT_CLAIM_TENANTID to "mobile",
-                                    Constants.JWT_CLAIM_AUTHORITIES to p.authorities))
-                    jwt = JwtRedis().apply {
-                        jti = token.jti
-                        uid = user.loginid
-                        status = TradeDict.JWT_STATUS_NORMAL
-                        expiration = token.expiration.valueInMillis
-                    }.apply {
-                        //删除之前的token
-                        if (!user.jti.isNullOrEmpty()) {
-                            apiJwtRepository.deleteById(user.jti!!)
-                        }
-                        apiJwtRepository.save(this)
-                    }
-                    user.jti = jwt.jti
+        var tk = ""
+        jwtRequestData.jwtToken?.also {
+            val currentMillis = System.currentTimeMillis()
+            if (it.expiration - currentMillis < 60 * 60 * 12) {
+                val exp = systemUtilService.getSysparaValueAsInt(
+                        SysparaUtil.MOBILE_LOGIN_EXPIRE_IN_SECONDS, 60 * 60 * 24 * 3)
+                val builder = JwtTokenBuilder.create()
+                        .expiration(exp.toLong())
+                        .uid(user.uid)
+                        .issuer("payapi")
+                        .tenantId("mobile")
+                        .authorities(p.authorities.toList())
+                val token = jwtTenantService.generate(builder)
+                if (token.isPresent) {
+                    user.jti = token.get().jti
                     mobileApiService.saveUser(user)
-                    tk = token.jwtToken
+                    tk = token.get().jwt
+                    jwtTenantService.revoke(jwtRequestData.jwtToken)
+                } else {
+                    tk = jwtRequestData.jwtToken.jwt
                 }
             }
         }
         return JsonResult.ok("OK").put("now", System.currentTimeMillis())
                 ?.put("token", tk)!!
     }
+
     /**
      * 验证码生成,内部校验
      * */
@@ -625,9 +610,9 @@
                 ?.put("name", name)
                 ?.put("needrebind", needrebind)
                 ?.put("signed", signed)
-                ?.put("version","1")
-                ?.put("minversion","1")
-                ?.put("versionmsg","1")
+                ?.put("version", "1")
+                ?.put("minversion", "1")
+                ?.put("versionmsg", "1")
                 ?.put("userid", if (user.userid.isNullOrEmpty()) "" else user.userid)!!.put("t", t)!!
     }
 
@@ -666,7 +651,7 @@
         val pwdtimes = user.checkLoginpwdtime()
         if (pwdtimes == -1) {
             if (!user.jti.isNullOrEmpty()) {
-                apiJwtRepository.deleteById(user.jti!!)
+                jwtTenantService.revoke(jwtRequestData.jwtToken)
             }
             return JsonResult.error(-1, "原密码错误次数过多,将退出系统,请重新登录系统或点击忘记密码功能找回密码")
         } else if (pwdtimes == 1) {
@@ -760,9 +745,9 @@
         val user = mobileApiService.findUserById(p.name)
                 ?: return JsonResult.error("用户不存在,请注册")
         val resp = qrcodeService.encodeCode(user.uid)
-        return if(resp.retcode==0){
+        return if (resp.retcode == 0) {
             JsonResult.ok("ok").put("qrcode", resp.retmsg)!!
-        }else{
+        } else {
             JsonResult.error(resp.retmsg)
         }
     }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/security.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/security.kt
index 9db3122..8e1892a 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -1,18 +1,13 @@
 package com.supwisdom.dlpay
 
-import com.supwisdom.dlpay.framework.core.JwtConfig
-import com.supwisdom.dlpay.framework.core.JwtTokenUtil
 import com.supwisdom.dlpay.framework.core.PasswordBCryptConfig
-import com.supwisdom.dlpay.framework.redisrepo.ApiJwtRepository
 import com.supwisdom.dlpay.framework.security.MyAuthenticationFailureHandler
 import com.supwisdom.dlpay.framework.security.ValidateCodeSecurityConfig
 import com.supwisdom.dlpay.framework.service.impl.MultiTenantOperatorDetailService
-import com.supwisdom.dlpay.framework.util.Constants
-import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.mobile.AuthLoginFailHandler
 import com.supwisdom.dlpay.mobile.AuthLoginSuccessHandler
 import com.supwisdom.dlpay.mobile.service.MobileUserService
-import org.jose4j.jwt.ReservedClaimNames
+import com.supwisdom.multitenant.jwt.JwtRequestData
 import org.jose4j.jwt.consumer.InvalidJwtException
 import org.jose4j.lang.JoseException
 import org.springframework.beans.factory.annotation.Autowired
@@ -42,6 +37,7 @@
 import org.springframework.web.filter.OncePerRequestFilter
 import java.security.SecureRandom
 import java.util.*
+import javax.annotation.Resource
 import javax.servlet.FilterChain
 import javax.servlet.http.HttpServletRequest
 import javax.servlet.http.HttpServletResponse
@@ -50,60 +46,19 @@
 
 @Component
 class ApiJwtAuthenticationFilter : OncePerRequestFilter() {
-    @Autowired
-    lateinit var jwtConfig: JwtConfig
 
-    @Autowired
-    lateinit var apiJwtRepository: ApiJwtRepository
-
-    private var jwtUtil: JwtTokenUtil? = null
-
-    private fun getUtil(): JwtTokenUtil {
-        if (jwtUtil == null) {
-            jwtUtil = JwtTokenUtil((jwtConfig))
-        }
-        return jwtUtil as JwtTokenUtil
-    }
+    @Resource(name = "jwtRequestData")
+    private lateinit var jwtRequestData: JwtRequestData
 
     override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
-        request.getHeader(jwtConfig.header)?.let { authHeader ->
+        jwtRequestData.jwtToken?.let { jwt ->
             try {
-                val jwt = if (authHeader.startsWith(jwtConfig.tokenHeader)) {
-                    authHeader.substring(jwtConfig.tokenHeader.length)
-                } else {
-                    throw JoseException("JWT Header error")
-                }
-                val claims = getUtil().verifyToken(jwt)
-                apiJwtRepository.findById(claims[ReservedClaimNames.JWT_ID].toString()).let {
-                    if (!it.isPresent) {
-                        throw JoseException("JWT has not been register")
-                    }
-                    // token 已被设为黑名单
-                    if (it.get().status != TradeDict.JWT_STATUS_NORMAL) {
-                        throw JoseException("JWT status error : ${it.get().status}")
-                    }
-                }
-                if (jwtConfig.multiTenant) {
-                    val tenantId = request.getHeader(Constants.HEADER_TETANTID)
-                    if (tenantId == null) {
-                        response.status = HttpStatus.UNAUTHORIZED.value()
-                        return
-                    }
-                    if (claims[Constants.JWT_CLAIM_TENANTID] != tenantId) {
-                        response.status = HttpStatus.UNAUTHORIZED.value()
-                        return
-                    }
-                }
-                val auth = UsernamePasswordAuthenticationToken(claims[Constants.JWT_CLAIM_UID], null,
-                        (claims[Constants.JWT_CLAIM_AUTHORITIES] as ArrayList<*>)
+                val auth = UsernamePasswordAuthenticationToken(jwt.uid, null,
+                        (jwt.authorities as ArrayList<*>)
                                 .map { SimpleGrantedAuthority(it as String) })
                 SecurityContextHolder.getContext().authentication = auth
             } catch (e: InvalidJwtException) {
                 SecurityContextHolder.clearContext()
-                if (e.hasExpired()) {
-                    // jwt 过期后返回 401
-                    apiJwtRepository.deleteById(e.jwtContext.jwtClaims.jwtId)
-                }
                 response.status = HttpStatus.UNAUTHORIZED.value()
                 return
             } catch (e: JoseException) {
@@ -126,20 +81,9 @@
 
 @Component
 class MobileSecurityFilter : OncePerRequestFilter() {
-    @Autowired
-    lateinit var jwtConfig: JwtConfig
 
-    @Autowired
-    lateinit var apiJwtRepository: ApiJwtRepository
-
-    private var jwtUtil: JwtTokenUtil? = null
-
-    private fun getUtil(): JwtTokenUtil {
-        if (jwtUtil == null) {
-            jwtUtil = JwtTokenUtil((jwtConfig))
-        }
-        return jwtUtil as JwtTokenUtil
-    }
+    @Resource(name = "jwtRequestData")
+    private lateinit var jwtRequestData: JwtRequestData
 
     override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
         var context: String? = request.contextPath
@@ -159,44 +103,14 @@
             filterChain.doFilter(request, response)
             return
         }
-        request.getHeader(jwtConfig.header)?.let { authHeader ->
+        jwtRequestData.jwtToken?.let { jwt ->
             try {
-                val jwt = if (authHeader.startsWith(jwtConfig.tokenHeader)) {
-                    authHeader.substring(jwtConfig.tokenHeader.length)
-                } else {
-                    throw JoseException("JWT Header error")
-                }
-                val claims = getUtil().verifyToken(jwt)
-                apiJwtRepository.findById(claims[ReservedClaimNames.JWT_ID].toString()).let {
-                    if (!it.isPresent) {
-                        throw JoseException("JWT has not been register")
-                    }
-                    // token 已被设为黑名单
-                    if (it.get().status != TradeDict.JWT_STATUS_NORMAL) {
-                        throw JoseException("JWT status error : ${it.get().status}")
-                    }
-                }
-                if (jwtConfig.multiTenant) {
-                    val tenantId = request.getHeader(Constants.HEADER_TETANTID)
-                    if (tenantId == null) {
-                        response.status = HttpStatus.UNAUTHORIZED.value()
-                        return
-                    }
-                    if (claims[Constants.JWT_CLAIM_TENANTID] != tenantId) {
-                        response.status = HttpStatus.UNAUTHORIZED.value()
-                        return
-                    }
-                }
-                val auth = UsernamePasswordAuthenticationToken(claims[Constants.JWT_CLAIM_UID], null,
-                        (claims[Constants.JWT_CLAIM_AUTHORITIES] as ArrayList<*>)
+                val auth = UsernamePasswordAuthenticationToken(jwt.uid, null,
+                        (jwt.authorities as ArrayList<*>)
                                 .map { SimpleGrantedAuthority(it as String) })
                 SecurityContextHolder.getContext().authentication = auth
             } catch (e: InvalidJwtException) {
                 SecurityContextHolder.clearContext()
-                if (e.hasExpired()) {
-                    // jwt 过期后返回 401
-                    apiJwtRepository.deleteById(e.jwtContext.jwtClaims.jwtId)
-                }
                 response.status = HttpStatus.UNAUTHORIZED.value()
                 return
             } catch (e: JoseException) {
@@ -373,6 +287,11 @@
                 // 设置 Web MVC 应用权限
                 http.apply(validateCodeSecurityConfig)
                         .and()
+                        .headers { headers ->
+                            headers.xssProtection { xssProtection ->
+                                xssProtection.xssProtectionEnabled(true)
+                            }
+                        }
                         .authorizeRequests()
                         .antMatchers("/login", "/login/form", "/mobileapi/**", "/userinfor").permitAll()
                         .antMatchers("/static/**").permitAll()
@@ -395,6 +314,7 @@
                         .deleteCookies("JSESSIONID")
                         .invalidateHttpSession(true)
                         .and().csrf().ignoringAntMatchers("oauth/**")
+
                 // 设置 Web MVC 应用权限
 //                http.apply(validateCodeSecurityConfig)
 //                        .and()
diff --git a/payapi/src/main/resources/application.properties b/payapi/src/main/resources/application.properties
index 906a5be..377a873 100644
--- a/payapi/src/main/resources/application.properties
+++ b/payapi/src/main/resources/application.properties
@@ -32,8 +32,8 @@
 ## quartz task scheduler
 shopbalance.updater.cron=*/10 * * * * ?
 dayend.settletask.cron=0 3/30 2-3 * * ?
-query.third.transdtl.result.cron=7 0/1 * * * ?
-payapi.sourcetype.checker.scheduler=7 3/10 * * * ?
+query.third.transdtl.result.cron=-
+payapi.sourcetype.checker.scheduler=-
 citizencard.dolosstask.cron=-
 ################################################
 # user password
diff --git a/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/security_controller_test.kt b/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/security_controller_test.kt
index 24853db..65bd05b 100644
--- a/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/security_controller_test.kt
+++ b/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/security_controller_test.kt
@@ -1,8 +1,8 @@
 package com.supwisdom.dlpay.controller
 
 import com.supwisdom.dlpay.MvcBaseTest
-import com.supwisdom.dlpay.framework.core.JwtConfig
 import com.supwisdom.dlpay.framework.util.HmacUtil
+import com.supwisdom.multitenant.jwt.config.JwtProperties
 import io.restassured.RestAssured
 import io.restassured.RestAssured.*
 import io.restassured.http.ContentType
@@ -28,7 +28,7 @@
     private var port: Int = 0
 
     @Autowired
-    lateinit var jwtConfig: JwtConfig
+    private lateinit var jwtProperties: JwtProperties
 
     @Before
     fun setUp() {
@@ -96,7 +96,7 @@
     @Test
     fun testJwtRefresh() {
         getJwt(appid, appsecret).also { jwt ->
-            given().header(jwtConfig.header, "${jwtConfig.tokenHeader}$jwt")
+            given().header(jwtProperties.jwtHeader, "${jwtProperties.schema} $jwt")
                     .`when`()
                     .get("/api/auth/refresh")
                     .then()
diff --git a/ynrcc-agent/Dockerfile b/ynrcc-agent/Dockerfile
index 3305510..41018d3 100644
--- a/ynrcc-agent/Dockerfile
+++ b/ynrcc-agent/Dockerfile
@@ -1,6 +1,7 @@
 FROM openjdk:8
+ARG BUILD_VERSION
 
-COPY ynrcc-agent-1.jar /opt/agent/agent.jar
+COPY ynrcc-agent-${BUILD_VERSION}.jar /opt/agent/agent.jar
 
 EXPOSE 8080
 
diff --git a/ynrcc-agent/build.gradle b/ynrcc-agent/build.gradle
index 01a06b5..4d1c0fa 100644
--- a/ynrcc-agent/build.gradle
+++ b/ynrcc-agent/build.gradle
@@ -13,8 +13,10 @@
 
 println("Build version: $buildVersion")
 
+
 bootJar {
     mainClassName = ynrccStartClass
+    archiveFileName = "${project.name}-${buildVersion}.${archiveExtension.getOrElse('.jar')}"
     manifest {
         attributes('YnrccAgent-Version': buildVersion)
     }
@@ -43,12 +45,11 @@
     }
     println("Docker image tag : ${imageVersion}")
     name "${dockerRegistry}/ynrcc:${imageVersion}"
-    println(jar.archiveFile.get())
-    files jar.archiveFile.get()
+    println(bootJar.archiveFile.get())
+    files bootJar.archiveFile.get()
+    buildArgs([BUILD_VERSION: "${buildVersion}"])
 }
 
-docker.dependsOn(jar)
-
 dependencies {
 
     implementation project(":payapi-common")