ソースを参照

修复跨域问题

fuyuchuan 3 週間 前
コミット
56a2d7294f

+ 1 - 1
flow-app/src/main/resources/application-dev.yml

@@ -65,7 +65,7 @@ spring:
 
 flowable:
   #关闭定时任务JOB
-  async-executor-activate: true
+  async-executor-activate: false
   # 是否应激活异步历史执行器。
   async-history-executor-activate: false
   # 是否需要自动部署流程定义。

+ 18 - 1
flow-common/flow-common-oauth2-starter/src/main/java/com/flow/common/oauth2/configure/AuthenticationKeyGenerator.java

@@ -39,4 +39,21 @@ public class AuthenticationKeyGenerator extends DefaultAuthenticationKeyGenerato
         // values.put("tenantId", "我是租户id");
         return generateKey(values);
     }
-}
+
+    // @Override
+    // public String extractKey(OAuth2Authentication authentication) {
+    //     Map<String, String> values = new LinkedHashMap<>();
+    //     OAuth2Request authorizationRequest = authentication.getOAuth2Request();
+    //     if (!authentication.isClientOnly()) {
+    //         values.put(USERNAME, authentication.getName());
+    //     }
+    //     values.put(CLIENT_ID, authorizationRequest.getClientId());
+    //     if (authorizationRequest.getScope() != null) {
+    //         values.put(SCOPE, OAuth2Utils.formatParameterList(new TreeSet<>(authorizationRequest.getScope())));
+    //     }
+    //     values.put("login_type", (String) authorizationRequest.getRequestParameters().get("login_type"));
+    //     values.put("uuid", UUID.randomUUID().toString());
+    //     return generateKey(values);
+    // }
+
+}

+ 58 - 10
flow-common/flow-common-oauth2-starter/src/main/java/com/flow/common/oauth2/configure/ResourceServerConfigure.java

@@ -3,6 +3,7 @@ package com.flow.common.oauth2.configure;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
+import org.springframework.context.annotation.Bean;
 import org.springframework.http.HttpMethod;
 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -13,6 +14,9 @@ import org.springframework.security.oauth2.config.annotation.web.configurers.Res
 import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.access.AccessDeniedHandler;
 
+import javax.servlet.http.HttpServletResponse;
+
+
 @EnableResourceServer
 @EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true, securedEnabled = true, jsr250Enabled = true)
 @EnableAutoConfiguration(exclude = UserDetailsServiceAutoConfiguration.class)
@@ -24,21 +28,47 @@ public class ResourceServerConfigure extends ResourceServerConfigurerAdapter {
 
     @Override
     public void configure(HttpSecurity http) throws Exception {
-        http     //关闭csrf保护
+        http
+                //.cors().configurationSource(corsConfigurationSource()).and()
+                //.cors().and()
                 .csrf().disable()
-                //不使用session
+
+                // 跨域异常处理
+                // .exceptionHandling()
+                // .authenticationEntryPoint((request, response, authException) -> {
+                //     // 手动添加 CORS 头
+                //     response.setHeader("Access-Control-Allow-Origin", "*");
+                //     response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
+                //     response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
+                //
+                //     // 返回 JSON 格式的错误信息
+                //     response.setContentType("application/json;charset=UTF-8");
+                //     response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+                //     response.getWriter().write(
+                //             "{\"code\": 401, \"message\": \"Token 无效或已过期,请重新登录\"}"
+                //     );
+                // })
+                // .and()
+
                 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                 .and()
-                // 认证请求
                 .authorizeRequests()
-                //放行预请求
                 .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                 .antMatchers("/static/file/**").permitAll()
-                .antMatchers("/auth/login", "/auth/code", "/auth/logout", "/user/list", "/model/download").permitAll()
-                // websocket路径放行
-                .antMatchers("/socket/**", "/api/socket/**").permitAll()
-                // 其他所有请求都需要认证
-                .anyRequest().authenticated();
+                .antMatchers("/auth/login",
+                        "/auth/code",
+                        "/auth/logout",
+                        "/auth/saltLogin",
+                        "/auth/getTimeStamp",
+                        "/user/list",
+                        "/model/download",
+                        "/user/list").permitAll()
+                .antMatchers("/socket/**").permitAll()
+                .anyRequest().authenticated()
+                .and()
+                .exceptionHandling()
+                .accessDeniedHandler(accessDeniedHandler)
+                .authenticationEntryPoint(authenticationEntryPoint);
     }
 
     @Override
@@ -54,4 +84,22 @@ public class ResourceServerConfigure extends ResourceServerConfigurerAdapter {
             resources.accessDeniedHandler(accessDeniedHandler);
         }
     }
-}
+
+    // @Bean
+    // public CorsConfigurationSource corsConfigurationSource() {
+    //     CorsConfiguration configuration = new CorsConfiguration();
+    //     // 设置允许的来源
+    //     configuration.addAllowedOriginPattern("*");
+    //     // 配置允许的HTTP方法
+    //     configuration.addAllowedMethod("*");
+    //     // 配置允许的请求头
+    //     configuration.addAllowedHeader("*");
+    //     // 允许凭证(如Cookie)跨域
+    //     configuration.setAllowCredentials(true);
+    //
+    //     UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+    //     source.registerCorsConfiguration("/**", configuration);
+    //     return source;
+    // }
+
+}

+ 35 - 6
flow-file/flow-file-biz/src/main/java/com/flow/config/WebAppConfigurer.java

@@ -10,6 +10,7 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 import javax.servlet.MultipartConfigElement;
+import java.io.File;
 
 @Configuration
 public class WebAppConfigurer implements WebMvcConfigurer {
@@ -25,24 +26,52 @@ public class WebAppConfigurer implements WebMvcConfigurer {
         WebMvcConfigurer.super.addResourceHandlers(registry);
     }
 
+    // @Override
+    // public void addResourceHandlers(ResourceHandlerRegistry registry) {
+    //     String path = FileConstant.getPath();
+    //     // 保证路径以 / 或 \\ 结尾
+    //     if (!path.endsWith(File.separator)) {
+    //         path += File.separator;
+    //     }
+    //     registry.addResourceHandler("/static/file/**")
+    //             .addResourceLocations("file:" + path)
+    //             .setCachePeriod(0);
+    // }
+
     @Override
     public void addCorsMappings(CorsRegistry registry) {
         registry
-                // 所有接口
                 .addMapping("/**")
-                // 允许跨域请求的域名
+                // 方案一:允许所有 origin(不带 credentials)
                 .allowedOrigins("*")
-                // 是否发送 Cookie
-                .allowCredentials(true)
-                // 所有请求方法
                 .allowedMethods("*")
-                // 允许的 Header
                 .allowedHeaders("*")
+                // 方案二:指定 origin + 允许 credentials
+                // .allowedOrigins("https://yourdomain.com")
+                // .allowCredentials(true)
                 // 允许的响应 Header
                 .exposedHeaders("*")
                 .maxAge(3600);
     }
 
+    // @Override
+    // public void addCorsMappings(CorsRegistry registry) {
+    //     registry
+    //             // 所有接口
+    //             .addMapping("/**")
+    //             // 允许跨域请求的域名
+    //             .allowedOrigins("*")
+    //             // 是否发送 Cookie
+    //             .allowCredentials(true)
+    //             // 所有请求方法
+    //             .allowedMethods("*")
+    //             // 允许的 Header
+    //             .allowedHeaders("*")
+    //             // 允许的响应 Header
+    //             .exposedHeaders("*")
+    //             .maxAge(3600);
+    // }
+
 
     /**
      * 文件上传配置

+ 8 - 0
flow-oauth/flow-oauth-api/src/main/java/com/flow/service/AuthService.java

@@ -10,6 +10,8 @@ public interface AuthService{
 
     ImageCode getImageCode();
 
+    AccessToken loginByUsername(String username);
+
     AccessToken login(LoginForm loginForm);
 
     void logout();
@@ -19,4 +21,10 @@ public interface AuthService{
     Permission permissions();
 
     List<Route> buildMenu(List<Menu> menus);
+
+    // salt登录
+    AccessToken saltLogin(String salt);
+
+    // 获取时间戳
+    Long getTimeStamp();
 }

+ 12 - 0
flow-oauth/flow-oauth-biz/pom.xml

@@ -30,6 +30,18 @@
             <artifactId>easy-captcha</artifactId>
             <version>1.6.2</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20210307</version>
+        </dependency>
+        <dependency>
+            <groupId>com.flow</groupId>
+            <artifactId>flow-system-biz</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
 </project>

+ 10 - 10
flow-oauth/flow-oauth-biz/src/main/java/com/flow/handler/CustomAuthenticationEntryPoint.java

@@ -25,27 +25,27 @@ public class CustomAuthenticationEntryPoint extends OAuth2AuthenticationEntryPoi
     public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
         Throwable cause = authException.getCause();
         if (cause instanceof OAuth2AccessDeniedException) {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "资源不在范围内");
+            Result.sendError(HttpStatus.FORBIDDEN.value(), "资源没有访问权限");
         } else if (cause instanceof UnapprovedClientAuthenticationException) {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "未经批准的客户端身份验证");
+            Result.sendError(HttpStatus.UNAUTHORIZED.value(), "未经批准的客户端身份验证");
         } else if (cause instanceof InvalidTokenException) {
             Result.sendError(HttpStatus.UNAUTHORIZED.value(), "登录已过期,请重新登录");
         } else if (cause instanceof InsufficientAuthenticationException) {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "访问此资源需要完成身份验证");
+            Result.sendError(HttpStatus.UNAUTHORIZED.value(), "访问此资源需要完成身份验证");
         } else if (cause instanceof BadCredentialsException) {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "客户端异常");
+            Result.sendError(HttpStatus.UNAUTHORIZED.value(), "客户端异常");
         } else if (cause instanceof UsernameNotFoundException) {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "用户不存在");
+            Result.sendError(HttpStatus.NOT_FOUND.value(), "用户不存在");
         } else if (cause instanceof LockedException) {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "账户已锁定");
+            Result.sendError(HttpStatus.LOCKED.value(), "账户已锁定");
         } else if (cause instanceof AccountExpiredException) {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "账户已过期");
+            Result.sendError(HttpStatus.FORBIDDEN.value(), "账户已过期");
         } else if (cause instanceof CredentialsExpiredException) {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "凭据过期");
+            Result.sendError(HttpStatus.UNAUTHORIZED.value(), "凭据过期");
         } else if (cause instanceof DisabledException) {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "账户已禁用");
+            Result.sendError(HttpStatus.FORBIDDEN.value(), "账户已禁用");
         } else {
-            Result.sendError(HttpStatus.BAD_REQUEST.value(), "该资源没有访问权限");
+            Result.sendError(HttpStatus.FORBIDDEN.value(), "该资源没有访问权限");
         }
     }
 }

+ 150 - 17
flow-oauth/flow-oauth-biz/src/main/java/com/flow/service/impl/AuthServiceImpl.java

@@ -1,6 +1,5 @@
 package com.flow.service.impl;
 
-
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.flow.common.core.exception.BaseException;
 import com.flow.common.core.util.ApplicationContextUtil;
@@ -11,26 +10,41 @@ import com.flow.entity.User;
 import com.flow.model.*;
 import com.flow.service.AuthService;
 import com.wf.captcha.ArithmeticCaptcha;
+import lombok.extern.slf4j.Slf4j;
+import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.oauth2.common.OAuth2AccessToken;
-import org.springframework.security.oauth2.provider.ClientDetails;
-import org.springframework.security.oauth2.provider.ClientDetailsService;
-import org.springframework.security.oauth2.provider.TokenRequest;
+import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
+import org.springframework.security.oauth2.provider.*;
 import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
 import org.springframework.security.oauth2.provider.token.TokenStore;
 import org.springframework.stereotype.Service;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 
 import javax.servlet.http.HttpServletRequest;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+import javax.crypto.Cipher;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
+@Slf4j
 @Service
 public class AuthServiceImpl implements AuthService {
+
     @Autowired
     private ClientDetailsService clientDetailsService;
     @Autowired
@@ -39,6 +53,26 @@ public class AuthServiceImpl implements AuthService {
     private StringRedisTemplate redisTemplate;
     @Autowired
     private AuthDao authDao;
+    @Autowired
+    private UserDetailsService userDetailsService;
+    @Autowired
+    private AuthorizationServerTokenServices tokenServices;
+
+
+    private static final String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALE9Y/QdMET28R4z\n" +
+            "fhDHTdTyhWYLrEipY9G4jm3wnTMQNC50CBco+PLwTRDdxfzTRQ0FPHaBR9FE2s42\n" +
+            "oAsoOcnVITqoJQN5c57Pyxr3kZD13gFfulKNkus9+cIFMG1vksaRjnOaWa2kbYBX\n" +
+            "14mv6RCqGz+vRziePBoONUbiQXdlAgMBAAECgYBjSDdAXEVYrFdeiouYjHwdyAhP\n" +
+            "pERKo5BFvzMRhJIaM353cwnBJ3NkapVQ2Fn6iMIKTB+VZk+7eu1yTAkUluDfLowd\n" +
+            "REZS4ipOBY5UuNnjbXmSOoUQw6vRnox0X4x6S1vd4FBHgpVe1VkiE7Nz5U7Clyd5\n" +
+            "yw2P1lHwMyB/guAH4QJBAN3dGkMASj0jm23maHOfehp/zlACB8HpMKuV4z/bEg45\n" +
+            "nC9Hw5NloUHrXdzEXP1+S46MCH2THflxDVYtnZTRLO0CQQDMgp3Jrn7kkKtNceZF\n" +
+            "R08hLbVmfNlatgONgFJ5JnR+GTQ6o2gwM6SLyoBkfAIiEDpr6c6nBXTU09GOYxBk\n" +
+            "+h1ZAkB32pXxVBrG5JF20V3j+GcyIZEGz9H5A0xzpUlambIrVRv2vsH8wo5W2hue\n" +
+            "w8Woe629mBCOJgevVU9rGsFiP44RAkEApbTYAQjAjJakFpZJjKzg8vNEXoye2R9N\n" +
+            "9aOaL8v27A2kAjdRPm050IL+UW0hlVQs4i+KYE7NgX03+PVP3WHD0QJBANLo4PRw\n" +
+            "7Y+dLPAzuazsD3/5SYaSh+KSD/+tVbc6CFvLyfFUKp/a4PzzvGaLo/Ky/ffOY5k0\n" +
+            "hmavbHCKcg+r+hg=";
 
     @Override
     public ImageCode getImageCode() {
@@ -52,8 +86,102 @@ public class AuthServiceImpl implements AuthService {
         return new ImageCode(captcha.toBase64(), uuid);
     }
 
+    // 盐值登录
+    @Override
+    public AccessToken saltLogin(String salt) {
+        AccessToken accessToken = null;
+        long now = System.currentTimeMillis();
+        String decryptedData = null;
+        try {
+            decryptedData = decrypt(salt);
+        } catch (Exception e) {
+            throw new BaseException("盐值解析异常,请联系管理员" + e.getMessage());
+        }
+        log.info("解密后的数据: " + decryptedData);
+
+        if (StringUtils.isBlank(decryptedData)) {
+            throw new BaseException("盐值数据为空,请联系管理员");
+        } else {
+            JSONObject jsonObject = new JSONObject(decryptedData);
+
+            String user = jsonObject.getString("user");
+            long time = jsonObject.getLong("time");
+            String form = jsonObject.getString("form");
+
+            // 判断时间戳是否过期
+            // if (now - time < 10000) {
+            //     throw new BaseException("请求超时,请重试");
+            // } else {
+            //
+            // }
+            if (StringUtils.isNotBlank(user)) {
+                 accessToken = loginByUsername(user);
+            }
+        }
+        return accessToken;
+    }
+
+    // RSA解密
+    public String decrypt(String encryptedData) throws Exception {
+        String privateKeyBase64 = PRIVATE_KEY.replaceAll("\\s", "");
+        // 将Base64编码的私钥转换为PrivateKey对象
+        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyBase64);
+
+        // 生成PrivateKey对象
+        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
+
+        // 创建Cipher对象进行解密
+        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+        cipher.init(Cipher.DECRYPT_MODE, privateKey);
+
+        // 解密
+        encryptedData = encryptedData.replaceAll(" ", "+");
+        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
+        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
+
+        // 将解密后的字节转换为字符串
+        return new String(decryptedBytes, StandardCharsets.UTF_8);
+    }
+
+    // 获取时间戳
+    @Override
+    public Long getTimeStamp() {
+        return System.currentTimeMillis();
+    }
+
+    public AccessToken loginByUsername(String username) {
+        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+
+        ClientDetails clientDetails = clientDetailsService.loadClientByClientId("client");
+
+        // 直接创建OAuth2认证
+        OAuth2Request oauth2Request = new OAuth2Request(
+                Collections.emptyMap(),
+                clientDetails.getClientId(),
+                null,
+                true,
+                clientDetails.getScope(),
+                null,
+                null,
+                null,
+                null
+        );
+
+        Authentication userAuth = new UsernamePasswordAuthenticationToken(
+                userDetails, null, userDetails.getAuthorities());
+
+        OAuth2Authentication oauth2Authentication = new OAuth2Authentication(oauth2Request, userAuth);
+
+        // 直接生成token
+        OAuth2AccessToken token = tokenServices.createAccessToken(oauth2Authentication);
+        return new AccessToken(token);
+    }
+
     @Override
     public AccessToken login(LoginForm loginForm) {
+        OAuth2AccessToken oAuth2AccessToken = null;
         String uuid = loginForm.getUuid();
         String code = loginForm.getCode();
         if (StringUtils.isBlank(code) || StringUtils.isBlank(uuid)) {
@@ -66,6 +194,7 @@ public class AuthServiceImpl implements AuthService {
         if (!code.equalsIgnoreCase(redisCode)) {
             throw new BaseException("验证码错误");
         }
+
         HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
         request.setAttribute("login_type", "social_login");
         ClientDetails clientDetails = clientDetailsService.loadClientByClientId("client");
@@ -78,25 +207,29 @@ public class AuthServiceImpl implements AuthService {
                 clientDetails.getClientId(), clientDetails.getScope(),
                 requestParameters.get("grant_type")
         );
-        ResourceOwnerPasswordTokenGranter granter = ApplicationContextUtil.getBean(ResourceOwnerPasswordTokenGranter.class);
-        OAuth2AccessToken oAuth2AccessToken = granter.grant(tokenRequest.getGrantType(), tokenRequest);
+
+        try {
+            ResourceOwnerPasswordTokenGranter granter = ApplicationContextUtil.getBean(ResourceOwnerPasswordTokenGranter.class);
+            oAuth2AccessToken = granter.grant(tokenRequest.getGrantType(), tokenRequest);
+        } catch (InvalidGrantException ex) {
+            throw new BaseException("用户名或密码错误");
+        }
+
         return new AccessToken(oAuth2AccessToken);
     }
 
     @Override
     public void logout() {
-        try {
-            String accessToken = SecurityContextUtil.getAccessToken();
-            if (StringUtils.isNotBlank(accessToken)) {
-                OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(SecurityContextUtil.getAccessToken());
-                tokenStore.removeAccessToken(oAuth2AccessToken);
-                if (Objects.nonNull(oAuth2AccessToken.getRefreshToken())) {
-                    tokenStore.removeRefreshToken(oAuth2AccessToken.getRefreshToken());
-                }
-                SecurityContextHolder.getContext().setAuthentication(null);
-                SecurityContextHolder.clearContext();
+        String accessToken = SecurityContextUtil.getAccessToken();
+        if (StringUtils.isNotBlank(accessToken)) {
+            OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(SecurityContextUtil.getAccessToken());
+            tokenStore.removeAccessToken(oAuth2AccessToken);
+            if (Objects.nonNull(oAuth2AccessToken.getRefreshToken())) {
+                tokenStore.removeRefreshToken(oAuth2AccessToken.getRefreshToken());
             }
-        } catch (Exception ignored) {}
+            SecurityContextHolder.getContext().setAuthentication(null);
+            SecurityContextHolder.clearContext();
+        }
     }
 
     @Override

+ 14 - 1
flow-oauth/flow-oauth-controller/src/main/java/com/flow/controller/AuthController.java

@@ -20,12 +20,25 @@ public class AuthController {
     public Result<ImageCode> getImageCode() {
         return Result.success(authService.getImageCode());
     }
-
     @PostMapping("/login")
     public Result<AccessToken> login(@RequestBody LoginForm loginForm) {
         return Result.success(authService.login(loginForm));
     }
 
+    // 盐值登录
+    //@CrossOrigin(origins = "http://192.168.10.140:9089")
+    @PostMapping("/saltLogin")
+    public Result<AccessToken> saltLogin(@RequestParam String salt) {
+        return Result.success(authService.saltLogin(salt));
+    }
+
+    // 获取时间戳
+    //@CrossOrigin(origins = "http://192.168.10.140:9089")
+    @GetMapping("/getTimeStamp")
+    public Result<Long> getTimeStamp() {
+        return Result.success(authService.getTimeStamp());
+    }
+
     @PostMapping("/logout")
     public Result<?> logout() {
         authService.logout();

+ 1 - 0
flow-system/flow-system-biz/src/main/java/com/flow/service/impl/UserServiceImpl.java

@@ -138,6 +138,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserDao, User> implements U
         StorageFile storageFile = fileService.upload(multipartFile);
         userDao.lambdaUpdateChain()
                 .set(User::getAvatar, String.format("/api%s", storageFile.getUrl()))
+                //.set(User::getAvatar, storageFile.getUrl())
                 .eq(User::getUsername, SecurityContextUtil.getUserId())
                 .update();
         return storageFile;

+ 5 - 0
flow-workflow/flow-workflow-entity/src/main/java/com/flow/entity/FlowDefine.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.flow.common.mybatis.entity.BaseEntity;
@@ -20,6 +21,7 @@ import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import org.flowable.engine.repository.ProcessDefinition;
 
+import java.time.LocalDateTime;
 import java.util.*;
 
 @EqualsAndHashCode(callSuper = true)
@@ -58,6 +60,9 @@ public class FlowDefine extends BaseEntity {
     @TableField(exist = false)
     private Integer suspend;
 
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
     public FlowDefine(ProcessDefinition processDefinition) {
         this.defineId = processDefinition.getId();
         this.key = processDefinition.getKey();

+ 5 - 1
flow-workflow/flow-workflow-entity/src/main/java/com/flow/entity/FlowInstance.java

@@ -3,6 +3,8 @@ package com.flow.entity;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.flow.enums.ProcessStatus;
 import lombok.Data;
 
@@ -10,7 +12,7 @@ import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.List;
 import java.util.Objects;
-
+@JsonInclude(JsonInclude.Include.ALWAYS)
 @TableName(value = "flow_instance", autoResultMap = true)
 @Data
 public class FlowInstance {
@@ -28,8 +30,10 @@ public class FlowInstance {
     @TableField(exist = false)
     private String startUserId;
     @TableField(exist = false)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime startTime;
     @TableField(exist = false)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime endTime;
     @TableField(exist = false)
     private Long duration;

+ 4 - 0
flow-workflow/flow-workflow-entity/src/main/java/com/flow/entity/FlowTask.java

@@ -3,6 +3,7 @@ package com.flow.entity;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.flow.enums.ProcessStatus;
 import lombok.Data;
 import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
@@ -29,10 +30,13 @@ public class FlowTask {
     @TableField(exist = false)
     private String assignee;
     @TableField(exist = false)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime startTime;
     @TableField(exist = false)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime endTime;
     @TableField(exist = false)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime dueDate;
     @TableField(exist = false)
     private Long duration;

+ 3 - 0
flow-workflow/flow-workflow-entity/src/main/java/com/flow/model/FormInfo.java

@@ -1,5 +1,6 @@
 package com.flow.model;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.flow.entity.FlowDefine;
 import com.flow.entity.FormModel;
 import com.flow.entity.node.FieldProperty;
@@ -35,8 +36,10 @@ public class FormInfo {
     // 是否可撤销
     private Boolean isCancel = false;
     // 发起时间
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime startTime;
     // 结束时间
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime endTime;
     // 操作权限
     private Map<String, Boolean> operations = new LinkedHashMap<>();

+ 1 - 1
pom.xml

@@ -34,7 +34,7 @@
         <java.version>1.8</java.version>
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.target>1.8</maven.compiler.target>
-        <spring.boot-version>2.3.12.RELEASE</spring.boot-version>
+        <spring.boot-version>2.7.10</spring.boot-version>
         <mysql.version>8.0.21</mysql.version>
         <dm.version>8.1.2.192</dm.version>
         <guava.version>33.0.0-jre</guava.version>