Browse Source

Merge branch 'dev' of ssh://10.10.100.21/source/saas-platform into dev

guq 7 years ago
parent
commit
9a1119b7d6
20 changed files with 314 additions and 112 deletions
  1. 2 2
      base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/api/AccountApi.java
  2. 10 2
      base-servers/account/account-dto/src/main/java/com/usoftchina/saas/account/dto/AccountDTO.java
  3. 2 1
      base-servers/account/account-server/src/main/resources/application.yml
  4. 13 2
      base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/api/AuthApi.java
  5. 0 23
      base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/api/TokenApi.java
  6. 10 7
      base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/cache/TokenCache.java
  7. 4 0
      base-servers/auth/auth-dto/pom.xml
  8. 47 0
      base-servers/auth/auth-dto/src/main/java/com/usoftchina/saas/auth/dto/AuthDTO.java
  9. 9 0
      base-servers/auth/auth-server/pom.xml
  10. 58 5
      base-servers/auth/auth-server/src/main/java/com/usoftchina/saas/auth/controller/AuthController.java
  11. 29 7
      base-servers/auth/auth-server/src/main/resources/application.yml
  12. BIN
      base-servers/auth/auth-server/src/main/resources/auth/pub.key
  13. 38 0
      base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/config/AuthFilter.java
  14. 2 3
      base-servers/gateway-server/src/main/resources/application.yml
  15. 1 0
      framework/core/src/main/java/com/usoftchina/saas/exception/ExceptionCode.java
  16. 23 5
      frontend/saas-web/app/util/FormUtil.js
  17. 21 5
      frontend/saas-web/app/view/core/form/FormPanel.js
  18. 2 44
      frontend/saas-web/app/view/core/form/FormPanelController.js
  19. 43 0
      frontend/saas-web/app/view/core/form/field/DetailGridField.js
  20. 0 6
      frontend/saas-web/ext/build/ext-all-rtl-debug.js

+ 2 - 2
base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/api/AccountApi.java

@@ -19,7 +19,7 @@ public interface AccountApi {
      * @param password 明文密码
      * @param password 明文密码
      * @return
      * @return
      */
      */
-    @GetMapping(value = "/pwd/check")
+    @GetMapping(value = "/account/pwd/check")
     Result<AccountDTO> validByUsernameAndPwd(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password);
     Result<AccountDTO> validByUsernameAndPwd(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password);
 
 
     /**
     /**
@@ -28,6 +28,6 @@ public interface AccountApi {
      * @param username
      * @param username
      * @return
      * @return
      */
      */
-    @GetMapping
+    @GetMapping(value = "/account/read")
     Result<AccountDTO> getAccount(@RequestParam(value = "username") String username);
     Result<AccountDTO> getAccount(@RequestParam(value = "username") String username);
 }
 }

+ 10 - 2
base-servers/account/account-dto/src/main/java/com/usoftchina/saas/account/dto/AccountDTO.java

@@ -29,13 +29,12 @@ public class AccountDTO implements Serializable {
      * 所绑定的角色(按绑定的公司ID分组成Map)
      * 所绑定的角色(按绑定的公司ID分组成Map)
      */
      */
     private Map<Long, List<RoleBaseDTO>> rolesMap;
     private Map<Long, List<RoleBaseDTO>> rolesMap;
-
     /**
     /**
      * 所拥有的资源
      * 所拥有的资源
      *
      *
      * @return
      * @return
      */
      */
-
+    private Map<Long, List<UrlResourceDTO>> resourcesMap;
 
 
     public Long getId() {
     public Long getId() {
         return id;
         return id;
@@ -101,6 +100,14 @@ public class AccountDTO implements Serializable {
         this.rolesMap = rolesMap;
         this.rolesMap = rolesMap;
     }
     }
 
 
+    public Map<Long, List<UrlResourceDTO>> getResourcesMap() {
+        return resourcesMap;
+    }
+
+    public void setResourcesMap(Map<Long, List<UrlResourceDTO>> resourcesMap) {
+        this.resourcesMap = resourcesMap;
+    }
+
     @Override
     @Override
     public String toString() {
     public String toString() {
         return "AccountDTO{" +
         return "AccountDTO{" +
@@ -112,6 +119,7 @@ public class AccountDTO implements Serializable {
                 ", type=" + type +
                 ", type=" + type +
                 ", companies=" + companies +
                 ", companies=" + companies +
                 ", rolesMap=" + rolesMap +
                 ", rolesMap=" + rolesMap +
+                ", resourcesMap=" + resourcesMap +
                 '}';
                 '}';
     }
     }
 }
 }

+ 2 - 1
base-servers/account/account-server/src/main/resources/application.yml

@@ -40,13 +40,14 @@ eureka:
     leaseRenewalIntervalInSeconds: 10
     leaseRenewalIntervalInSeconds: 10
     health-check-url-path: /actuator/health
     health-check-url-path: /actuator/health
     status-page-url-path: /actuator/info
     status-page-url-path: /actuator/info
+    prefer-ip-address: true
     metadata-map:
     metadata-map:
       user.name: ${spring.security.user.name}
       user.name: ${spring.security.user.name}
       user.password: ${spring.security.user.password}
       user.password: ${spring.security.user.password}
   client:
   client:
     registryFetchIntervalSeconds: 5
     registryFetchIntervalSeconds: 5
     serviceUrl:
     serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@192.168.0.181:8510/eureka/
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:8500/eureka/
 server:
 server:
   port: 8580
   port: 8580
   tomcat:
   tomcat:

+ 13 - 2
base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/api/AuthApi.java

@@ -1,8 +1,10 @@
 package com.usoftchina.saas.auth.api;
 package com.usoftchina.saas.auth.api;
 
 
+import com.usoftchina.saas.auth.dto.AuthDTO;
 import com.usoftchina.saas.auth.dto.TokenDTO;
 import com.usoftchina.saas.auth.dto.TokenDTO;
 import com.usoftchina.saas.base.Result;
 import com.usoftchina.saas.base.Result;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RequestParam;
 
 
@@ -13,12 +15,21 @@ import org.springframework.web.bind.annotation.RequestParam;
 @FeignClient(name = "auth-server")
 @FeignClient(name = "auth-server")
 public interface AuthApi {
 public interface AuthApi {
     /**
     /**
-     * 登录认证获取token
+     * 登录认证获取token、公司列表
      *
      *
      * @param username
      * @param username
      * @param password
      * @param password
      * @return
      * @return
      */
      */
     @PostMapping(value = "/api/auth")
     @PostMapping(value = "/api/auth")
-    Result<TokenDTO> authorize(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password);
+    Result<AuthDTO> authorize(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password);
+
+    /**
+     * 切换公司
+     *
+     * @param companyId
+     * @return
+     */
+    @GetMapping(value = "/api/auth/switch/company")
+    Result<TokenDTO> switchCompany(@RequestParam(value = "companyId") String companyId);
 }
 }

+ 0 - 23
base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/api/TokenApi.java

@@ -1,23 +0,0 @@
-package com.usoftchina.saas.auth.api;
-
-import com.usoftchina.saas.auth.dto.TokenDTO;
-import com.usoftchina.saas.base.Result;
-import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-
-/**
- * @author yingp
- * @date 2018/9/30
- */
-@FeignClient(name = "auth-server")
-public interface TokenApi {
-    /**
-     * 登录获取token
-     *
-     * @param userName
-     * @return
-     */
-    @PostMapping(value = "/client/login")
-    Result<TokenDTO> login(@RequestParam(value = "userName") String userName);
-}

+ 10 - 7
base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/cache/TokenCache.java

@@ -1,6 +1,6 @@
 package com.usoftchina.saas.auth.cache;
 package com.usoftchina.saas.auth.cache;
 
 
-import com.usoftchina.saas.auth.api.TokenApi;
+import com.usoftchina.saas.auth.api.AuthApi;
 import com.usoftchina.saas.cache.RedisHashCache;
 import com.usoftchina.saas.cache.RedisHashCache;
 import com.usoftchina.saas.context.SpringContextHolder;
 import com.usoftchina.saas.context.SpringContextHolder;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.RedisTemplate;
@@ -15,16 +15,19 @@ public class TokenCache extends RedisHashCache<String, String, String> {
 
 
     private final String account;
     private final String account;
 
 
-    private final TokenApi tokenApi;
+    private final String password;
 
 
-    private TokenCache(String account) {
+    private final AuthApi authApi;
+
+    private TokenCache(String account, String password) {
         super(() -> SpringContextHolder.getBean(RedisTemplate.class));
         super(() -> SpringContextHolder.getBean(RedisTemplate.class));
         this.account = account;
         this.account = account;
-        this.tokenApi = SpringContextHolder.getBean(TokenApi.class);
+        this.password = password;
+        this.authApi = SpringContextHolder.getBean(AuthApi.class);
     }
     }
 
 
-    public static TokenCache of(String account) {
-        return new TokenCache(account);
+    public static TokenCache of(String account, String password) {
+        return new TokenCache(account, password);
     }
     }
 
 
     @Override
     @Override
@@ -39,6 +42,6 @@ public class TokenCache extends RedisHashCache<String, String, String> {
 
 
     @Override
     @Override
     protected Supplier<String> getSupplier() {
     protected Supplier<String> getSupplier() {
-        return () -> tokenApi.login(account).getData().getToken();
+        return () -> authApi.authorize(account, password).getData().getToken().getToken();
     }
     }
 }
 }

+ 4 - 0
base-servers/auth/auth-dto/pom.xml

@@ -13,6 +13,10 @@
     <description>authentication data transfer object</description>
     <description>authentication data transfer object</description>
 
 
     <dependencies>
     <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>account-dto</artifactId>
+        </dependency>
         <dependency>
         <dependency>
             <groupId>io.springfox</groupId>
             <groupId>io.springfox</groupId>
             <artifactId>springfox-swagger2</artifactId>
             <artifactId>springfox-swagger2</artifactId>

+ 47 - 0
base-servers/auth/auth-dto/src/main/java/com/usoftchina/saas/auth/dto/AuthDTO.java

@@ -0,0 +1,47 @@
+package com.usoftchina.saas.auth.dto;
+
+import com.usoftchina.saas.account.dto.CompanyBaseDTO;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2018/10/26
+ */
+public class AuthDTO implements Serializable{
+    private TokenDTO token;
+    private List<CompanyBaseDTO> companies;
+
+    public AuthDTO() {
+    }
+
+    public AuthDTO(TokenDTO token, List<CompanyBaseDTO> companies) {
+        this.token = token;
+        this.companies = companies;
+    }
+
+    public TokenDTO getToken() {
+        return token;
+    }
+
+    public void setToken(TokenDTO token) {
+        this.token = token;
+    }
+
+    public List<CompanyBaseDTO> getCompanies() {
+        return companies;
+    }
+
+    public void setCompanies(List<CompanyBaseDTO> companies) {
+        this.companies = companies;
+    }
+
+    @Override
+    public String toString() {
+        return "AuthDTO{" +
+                "token=" + token +
+                ", companies=" + companies +
+                '}';
+    }
+}

+ 9 - 0
base-servers/auth/auth-server/pom.xml

@@ -48,6 +48,15 @@
             <artifactId>springfox-swagger2</artifactId>
             <artifactId>springfox-swagger2</artifactId>
         </dependency>
         </dependency>
 
 
+        <!-- sleuth -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-zipkin</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.amqp</groupId>
+            <artifactId>spring-rabbit</artifactId>
+        </dependency>
         <dependency>
         <dependency>
             <groupId>net.logstash.logback</groupId>
             <groupId>net.logstash.logback</groupId>
             <artifactId>logstash-logback-encoder</artifactId>
             <artifactId>logstash-logback-encoder</artifactId>

+ 58 - 5
base-servers/auth/auth-server/src/main/java/com/usoftchina/saas/auth/controller/AuthController.java

@@ -5,27 +5,38 @@ import com.usoftchina.saas.account.dto.AccountDTO;
 import com.usoftchina.saas.auth.common.jwt.JwtHelper;
 import com.usoftchina.saas.auth.common.jwt.JwtHelper;
 import com.usoftchina.saas.auth.common.jwt.JwtInfo;
 import com.usoftchina.saas.auth.common.jwt.JwtInfo;
 import com.usoftchina.saas.auth.common.jwt.TokenVO;
 import com.usoftchina.saas.auth.common.jwt.TokenVO;
+import com.usoftchina.saas.auth.dto.AuthDTO;
 import com.usoftchina.saas.auth.dto.TokenDTO;
 import com.usoftchina.saas.auth.dto.TokenDTO;
 import com.usoftchina.saas.base.Result;
 import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.exception.ExceptionCode;
 import com.usoftchina.saas.utils.BeanMapper;
 import com.usoftchina.saas.utils.BeanMapper;
+import com.usoftchina.saas.utils.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
 /**
  * @author yingp
  * @author yingp
  * @date 2018/10/2
  * @date 2018/10/2
  */
  */
 @RestController
 @RestController
-@RequestMapping(path = "/api/auth")
+@RequestMapping
 public class AuthController {
 public class AuthController {
 
 
     @Autowired
     @Autowired
     private AccountApi accountApi;
     private AccountApi accountApi;
 
 
+    @Value("${auth.public-key}")
+    private String publicKeyPath;
+
     @Value("${auth.private-key}")
     @Value("${auth.private-key}")
     private String privateKeyPath;
     private String privateKeyPath;
 
 
+    @Value("${auth.header:Authorization}")
+    private String authHeader;
+
     @Value("${auth.expire:18000}")
     @Value("${auth.expire:18000}")
     private int expire;
     private int expire;
 
 
@@ -36,17 +47,59 @@ public class AuthController {
      * @param password
      * @param password
      * @return
      * @return
      */
      */
-    @PostMapping
-    public Result<TokenDTO> authorize(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password) {
+    @PostMapping("/authorize")
+    public Result<AuthDTO> authorize(@RequestParam String username, @RequestParam String password) {
         Result<AccountDTO> result = accountApi.validByUsernameAndPwd(username, password);
         Result<AccountDTO> result = accountApi.validByUsernameAndPwd(username, password);
         if (result.isSuccess()) {
         if (result.isSuccess()) {
             AccountDTO accountDTO = result.getData();
             AccountDTO accountDTO = result.getData();
+            Long companyId = null;
+            if (!CollectionUtils.isEmpty(accountDTO.getCompanies())) {
+                companyId = accountDTO.getCompanies().get(0).getId();
+            }
             // TODO
             // TODO
-            JwtInfo info = new JwtInfo(null, null, accountDTO.getId(), accountDTO.getUsername());
+            String appId = "trade-app";
+
+            JwtInfo info = new JwtInfo(appId, companyId, accountDTO.getId(), accountDTO.getUsername());
             TokenVO tokenVO = JwtHelper.generateToken(info, privateKeyPath, expire);
             TokenVO tokenVO = JwtHelper.generateToken(info, privateKeyPath, expire);
             TokenDTO tokenDTO = BeanMapper.map(tokenVO, TokenDTO.class);
             TokenDTO tokenDTO = BeanMapper.map(tokenVO, TokenDTO.class);
-            return Result.success(tokenDTO);
+            return Result.success(new AuthDTO(tokenDTO, accountDTO.getCompanies()));
         }
         }
         return Result.error(result.getCode(), result.getMessage());
         return Result.error(result.getCode(), result.getMessage());
     }
     }
+
+    /**
+     * 切换公司
+     *
+     * @param request
+     * @param companyId
+     * @return
+     */
+    @GetMapping("/switch/company")
+    public Result<TokenDTO> switchCompany(HttpServletRequest request, @RequestParam Long companyId) {
+        String token = request.getHeader(authHeader);
+        JwtInfo infoFromToken = JwtHelper.getInfoFromToken(token, publicKeyPath);
+        if (isCompanyAvailable(infoFromToken, companyId)) {
+            JwtInfo info = new JwtInfo(infoFromToken.getAppId(), companyId, infoFromToken.getUserId(),
+                    infoFromToken.getUserName());
+            TokenVO tokenVO = JwtHelper.generateToken(info, privateKeyPath, expire);
+            return Result.success(BeanMapper.map(tokenVO, TokenDTO.class));
+        }
+        return Result.error(ExceptionCode.COMPANY_NOT_BIND);
+    }
+
+    /**
+     * 指定公司是否可用:
+     * 公司是否存在 + 是否已绑定
+     *
+     * @param infoFromToken
+     * @param companyId
+     * @return
+     */
+    private boolean isCompanyAvailable(JwtInfo infoFromToken, Long companyId) {
+        Result<AccountDTO> accountDTO = accountApi.getAccount(infoFromToken.getUserName());
+        if (!CollectionUtils.isEmpty(accountDTO.getData().getCompanies())) {
+            return accountDTO.getData().getCompanies().stream().anyMatch(cmp -> cmp.getId().equals(companyId));
+        }
+        return false;
+    }
 }
 }

+ 29 - 7
base-servers/auth/auth-server/src/main/resources/application.yml

@@ -7,12 +7,32 @@ spring:
     user:
     user:
       name: admin
       name: admin
       password: select111***
       password: select111***
+  rabbitmq:
+    host: 192.168.0.176
+    port: 5672
+    virtual-host: dev
+    username: saas
+    password: select123***
+  zipkin:
+    sender:
+      type: rabbit
+    locator:
+      discovery:
+        enabled: true
+  sleuth:
+    sampler:
+      probability: 1.0
   datasource:
   datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://192.168.253.12:3306/saas_auth?characterEncoding=utf-8&useSSL=false
+    username: root
+    password: select111***
     hikari:
     hikari:
-      driver-class-name: com.mysql.cj.jdbc.Driver
-      jdbc-url: jdbc:mysql://192.168.253.12:3306/saas_auth?characterEncoding=utf-8&useSSL=false
-      username: root
-      password: select111***
+      minimum-idle: 5
+      maximum-pool-size: 50
+      idle-timeout: 30000
+      max-lifetime: 1800000
+      connection-timeout: 30000
   messages:
   messages:
     basename: i18n/messages
     basename: i18n/messages
 eureka:
 eureka:
@@ -20,15 +40,16 @@ eureka:
     leaseRenewalIntervalInSeconds: 10
     leaseRenewalIntervalInSeconds: 10
     health-check-url-path: /actuator/health
     health-check-url-path: /actuator/health
     status-page-url-path: /actuator/info
     status-page-url-path: /actuator/info
+    prefer-ip-address: true
     metadata-map:
     metadata-map:
       user.name: ${spring.security.user.name}
       user.name: ${spring.security.user.name}
       user.password: ${spring.security.user.password}
       user.password: ${spring.security.user.password}
   client:
   client:
     registryFetchIntervalSeconds: 5
     registryFetchIntervalSeconds: 5
     serviceUrl:
     serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@192.168.0.181:8510/eureka/
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:8500/eureka/
 server:
 server:
-  port: 8580
+  port: 8600
   tomcat:
   tomcat:
     uri-encoding: UTF-8
     uri-encoding: UTF-8
 info:
 info:
@@ -41,4 +62,5 @@ mybatis:
   type-aliases-package: com.usoftchina.saas.auth.po
   type-aliases-package: com.usoftchina.saas.auth.po
   mapper-locations: classpath:mapper/*.xml
   mapper-locations: classpath:mapper/*.xml
 auth:
 auth:
-  private-key: auth/pri.key
+  private-key: auth/pri.key
+  public-key: auth/pub.key

BIN
base-servers/auth/auth-server/src/main/resources/auth/pub.key


+ 38 - 0
base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/config/AuthFilter.java

@@ -1,23 +1,61 @@
 package com.usoftchina.saas.gateway.config;
 package com.usoftchina.saas.gateway.config;
 
 
+import com.usoftchina.saas.auth.common.jwt.JwtHelper;
+import com.usoftchina.saas.auth.common.jwt.JwtInfo;
+import com.usoftchina.saas.exception.BizException;
+import com.usoftchina.saas.exception.ExceptionCode;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.cloud.gateway.filter.GatewayFilterChain;
 import org.springframework.cloud.gateway.filter.GatewayFilterChain;
 import org.springframework.cloud.gateway.filter.GlobalFilter;
 import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.context.annotation.Configuration;
 import org.springframework.core.Ordered;
 import org.springframework.core.Ordered;
+import org.springframework.http.server.reactive.ServerHttpRequest;
 import org.springframework.web.server.ServerWebExchange;
 import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 import reactor.core.publisher.Mono;
 
 
+import java.util.List;
+
 /**
 /**
  * 全局过滤器鉴权
  * 全局过滤器鉴权
  *
  *
  * @author yingp
  * @author yingp
  * @date 2018/10/13
  * @date 2018/10/13
  */
  */
+@Configuration
+@EnableConfigurationProperties(AuthConfig.class)
 public class AuthFilter implements GlobalFilter, Ordered {
 public class AuthFilter implements GlobalFilter, Ordered {
+
+    @Autowired
+    private AuthConfig authConfig;
+
     @Override
     @Override
     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+        if (!isIgnore(exchange.getRequest())) {
+            // 鉴别身份信息
+//            JwtInfo jwt = getJwtInfoFromHeader(exchange.getRequest());
+            // 鉴别角色权限
+        }
         return chain.filter(exchange);
         return chain.filter(exchange);
     }
     }
 
 
+    private boolean isIgnore(ServerHttpRequest request) {
+        String path = request.getPath().value();
+        return authConfig.getIgnores().stream().anyMatch(ignore -> ignore.equals(path));
+    }
+
+    private JwtInfo getJwtInfoFromHeader(ServerHttpRequest request) {
+        if (!request.getHeaders().containsKey(authConfig.getAuthHeader())) {
+            throw new BizException(ExceptionCode.JWT_ILLEGAL_ARGUMENT);
+        }
+        List<String> headers = request.getHeaders().get(authConfig.getAuthHeader());
+        if (headers.isEmpty()) {
+            throw new BizException(ExceptionCode.JWT_ILLEGAL_ARGUMENT);
+        }
+        String token = headers.get(0).trim();
+        return JwtHelper.getInfoFromToken(token, authConfig.getPublicKey());
+    }
+
     @Override
     @Override
     public int getOrder() {
     public int getOrder() {
         return -100;
         return -100;

+ 2 - 3
base-servers/gateway-server/src/main/resources/application.yml

@@ -153,8 +153,7 @@ info:
   spring-boot-version: '@spring.boot.version@'
   spring-boot-version: '@spring.boot.version@'
   spring-cloud-version: '@spring.cloud.version@'
   spring-cloud-version: '@spring.cloud.version@'
 auth:
 auth:
+  auth-header: Authorization
   public-key: auth/pub.key
   public-key: auth/pub.key
   ignores:
   ignores:
-    - /api/auth
-    # 忽略全部
-    - /
+    - /api/auth/authorize

+ 1 - 0
framework/core/src/main/java/com/usoftchina/saas/exception/ExceptionCode.java

@@ -26,6 +26,7 @@ public enum ExceptionCode implements BaseExceptionCode {
     COMPANY_CODE_EXIST(52001, "公司商业登记证号已注册"),
     COMPANY_CODE_EXIST(52001, "公司商业登记证号已注册"),
     COMPANY_DOMAIN_EXIST(52002, "域名已存在"),
     COMPANY_DOMAIN_EXIST(52002, "域名已存在"),
     COMPANY_NOT_EXIST(52003, "公司不存在"),
     COMPANY_NOT_EXIST(52003, "公司不存在"),
+    COMPANY_NOT_BIND(52004, "未绑定该公司"),
     USER_NAME_EXIST(53000, "用户名已注册"),
     USER_NAME_EXIST(53000, "用户名已注册"),
     USER_MOBILE_EXIST(53001, "手机号已注册"),
     USER_MOBILE_EXIST(53001, "手机号已注册"),
     USER_EMAIL_EXIST(53002, "邮箱已注册"),
     USER_EMAIL_EXIST(53002, "邮箱已注册"),

+ 23 - 5
frontend/saas-web/app/util/FormUtil.js

@@ -35,6 +35,11 @@ Ext.define('saas.util.FormUtil', {
                         Ext.apply(item, cusItem);
                         Ext.apply(item, cusItem);
                     });
                     });
                     Ext.Array.each(items, function(item) {
                     Ext.Array.each(items, function(item) {
+
+                        if(item.xtype == 'datefield') {
+                            item.format = 'Y-m-d H:i:s'
+                        }
+
                         if(item.xtype == 'numberfield') {
                         if(item.xtype == 'numberfield') {
                             Ext.applyIf(item, {
                             Ext.applyIf(item, {
                                 hideTrigger: true, // 隐藏trigger
                                 hideTrigger: true, // 隐藏trigger
@@ -62,6 +67,7 @@ Ext.define('saas.util.FormUtil', {
 
 
                             Ext.Array.each(columns, function(c) {
                             Ext.Array.each(columns, function(c) {
 
 
+
                                 // 不可锁定
                                 // 不可锁定
                                 Ext.applyIf(c, {
                                 Ext.applyIf(c, {
                                     lockable: false
                                     lockable: false
@@ -71,13 +77,25 @@ Ext.define('saas.util.FormUtil', {
                                 if(c.logic=='necessaryField'){
                                 if(c.logic=='necessaryField'){
                                     c.cls = 'x-grid-necessary';
                                     c.cls = 'x-grid-necessary';
                                 }
                                 }
+
+                                if(c.xtype == 'datecolumn') {
+                                    Ext.apply(c.xtype, {
+                                        format: 'Y-m-d H:i:s'
+                                    });
+                                }
                                 
                                 
                                 var editor = c.editor;
                                 var editor = c.editor;
-                                if(editor && editor.xtype == 'numberfield') {
-                                    Ext.applyIf(editor, {
-                                        hideTrigger: true, // 隐藏trigger
-                                        mouseWheelEnabled: false // 取消滚轮事件
-                                    });
+                                if(editor) {
+                                    if(editor.xtype == 'numberfield') {
+                                        Ext.applyIf(editor, {
+                                            hideTrigger: true, // 隐藏trigger
+                                            mouseWheelEnabled: false // 取消滚轮事件
+                                        });
+                                    }else if(editor.xtype == 'datefield') {
+                                        Ext.apply(editor, {
+                                            format: 'Y-m-d H:i:s'
+                                        });
+                                    }
                                 }
                                 }
                             });
                             });
 
 

+ 21 - 5
frontend/saas-web/app/view/core/form/FormPanel.js

@@ -169,10 +169,15 @@ Ext.define('saas.view.core.form.FormPanel', {
             allData = viewModel.getData(),
             allData = viewModel.getData(),
             bindFields = allData.base.bindFields,
             bindFields = allData.base.bindFields,
             detailCount = me.detailCount,
             detailCount = me.detailCount,
-            formData = {};
+            formData = {},
+            detailGrids = me.query('detailGridField');
 
 
         Ext.Array.each(bindFields, function(field) {
         Ext.Array.each(bindFields, function(field) {
-            formData[field] = allData[field];
+            var v = allData[field];
+            if(Ext.isDate(v)) {
+                v = Ext.Date.format(v, 'Y-m-d H:i:s');
+            }
+            formData[field] = v;
         });
         });
 
 
         var data = {
         var data = {
@@ -180,10 +185,21 @@ Ext.define('saas.view.core.form.FormPanel', {
         };
         };
 
 
         for (var i = 0; i < detailCount; i++) {
         for (var i = 0; i < detailCount; i++) {
-            var detail = allData['detail' + i],
-                store = detail.detailStore;
+            var g = detailGrids[i];
+            var gridDirtyData = g.getDirtyData();
+            var modelDetail = allData['detail' + i];
+            var detailBindFields = modelDetail.detailBindFields;
+
+            Ext.Array.each(gridDirtyData, function(d) {
+                for(k in d) {
+                    if(!Ext.Array.contains(detailBindFields, k)) {
+                        delete d[k];
+                    }
+                }
+            });
+            
 
 
-            data['detail' + i] = store.getData().items;
+            data['detail' + i] = gridDirtyData;
         }
         }
 
 
         return data;
         return data;

+ 2 - 44
frontend/saas-web/app/view/core/form/FormPanelController.js

@@ -77,28 +77,7 @@ Ext.define('saas.view.core.form.FormPanelController', {
         };
         };
 
 
         for(var i = 0; i < detailCount; i++) {
         for(var i = 0; i < detailCount; i++) {
-            var detailData = formData['detail' + i];
-            var modelDetail = modelData['detail' + i];
-            var dirtyGridData = [];
-            var detailBindFields = modelDetail.detailBindFields;
-
-            Ext.Array.each(detailData, function(item){
-                var d = Object.assign({}, item.data),
-                dirty = item.dirty;
-
-                if(dirty){
-                    if((typeof d.id) != "number" && d.id.indexOf('-')>-1){
-                        d.id = 0;
-                    }
-                    for(k in d) {
-                        if(!Ext.Array.contains(detailBindFields, k)) {
-                            delete d[k];
-                        }
-                    }
-                    dirtyGridData.push(d);
-                }
-            });
-            params['items' + ( i + 1)] = dirtyGridData;
+            params['items' + ( i + 1)] = formData['detail' + i];
         }
         }
 
 
         // 只有一个从表时从表字段改为items
         // 只有一个从表时从表字段改为items
@@ -147,28 +126,7 @@ Ext.define('saas.view.core.form.FormPanelController', {
         };
         };
 
 
         for(var i = 0; i < detailCount; i++) {
         for(var i = 0; i < detailCount; i++) {
-            var detailData = formData['detail' + i];
-            var modelDetail = modelData['detail' + i];
-            var dirtyGridData = [];
-            var detailBindFields = modelDetail.detailBindFields;
-
-            Ext.Array.each(detailData, function(item){
-                var d = Object.assign({}, item.data),
-                dirty = item.dirty;
-
-                if(dirty){
-                    if((typeof d.id) != "number" && d.id.indexOf('-')>-1){
-                        d.id = 0;
-                    }
-                    for(k in d) {
-                        if(!Ext.Array.contains(detailBindFields, k)) {
-                            delete d[k];
-                        }
-                    }
-                    dirtyGridData.push(d);
-                }
-            });
-            params['items' + ( i + 1)] = dirtyGridData;
+            params['items' + ( i + 1)] = formData['detail' + i];
         }
         }
 
 
         // 只有一个从表时从表字段改为items
         // 只有一个从表时从表字段改为items

+ 43 - 0
frontend/saas-web/app/view/core/form/field/DetailGridField.js

@@ -114,6 +114,12 @@ Ext.define('saas.view.core.form.field.DetailGridField', {
                 '</div>';
                 '</div>';
             },
             },
         };
         };
+
+        Ext.Array.each(columns, function(c) {
+            Ext.applyIf(c, {
+                allowBlank: true
+            });
+        });
         if (detnoField) {
         if (detnoField) {
             Ext.apply(me, { columns: [indexColumn].concat(columns) });
             Ext.apply(me, { columns: [indexColumn].concat(columns) });
         }
         }
@@ -287,6 +293,43 @@ Ext.define('saas.view.core.form.field.DetailGridField', {
                 typeof e.setDisabled == 'function' && e.setDisabled(!able);
                 typeof e.setDisabled == 'function' && e.setDisabled(!able);
             }
             }
         });
         });
+    },
+    isValid: function() {
+        var me = this,
+        columns = me.columns;
+
+        // 判断列必填
+        Ext.Array.each(columns, function(c) {
+            var allowBlank = c.allowBlank;
+            if(!allowBlank) {
+                
+            }
+        });
+    },
+
+    getDirtyData: function() {
+        var me = this,
+        store = me.getStore(),
+        allData = store.getData().items,
+        dirtyData = [];
+
+        Ext.Array.each(allData, function(item){
+            var d = Object.assign({}, item.data),
+            dirty = item.dirty;
+
+            if(dirty){
+                if((typeof d.id) != "number" && d.id.indexOf('-')>-1){
+                    d.id = 0;
+                }
+                for(k in d) {
+                    if(Ext.isDate(d[k])) {
+                        d[k] = Ext.Date.format(d[k], 'Y-m-d H:i:s');
+                    }
+                }
+                dirtyData.push(d);
+            }
+        });
+        return dirtyData;
     }
     }
 
 
 });
 });

+ 0 - 6
frontend/saas-web/ext/build/ext-all-rtl-debug.js

@@ -206312,12 +206312,6 @@ Ext.define('Ext.form.field.Date', {
             rawDate;
             rawDate;
         me.lastValue = me.rawDateText;
         me.lastValue = me.rawDateText;
         me.lastDate = me.rawDate;
         me.lastDate = me.rawDate;
-        //解析后台日期格式为 Y-m-d
-        if(v&&(typeof v) == "string"&&v.indexOf('.')==19&&v.indexOf('T')==10){
-            var d = new Date(v);
-            var times=d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate(); //+ ' ' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds(); 
-            v = times;
-        }
         if (Ext.isDate(v)) {
         if (Ext.isDate(v)) {
             rawDate = me.rawDate = v;
             rawDate = me.rawDate = v;
             me.rawDateText = me.formatDate(v);
             me.rawDateText = me.formatDate(v);