Przeglądaj źródła

add 新增验证码
fix 请求时间戳验证采用绝对值

A17404李放 3 lat temu
rodzic
commit
74f4fee410

+ 2 - 2
coffee-admin/src/main/resources/application-dev.yml

@@ -101,10 +101,10 @@ spring:
         max-wait: -1ms
 request:
   check:
-    enable: true
+    enable: false
     # 开启请求验签
     sign: true
-    # 请求过期时间 10分钟
+    # 请求与服务器时间间隔不得超过 10分钟
     expire-interval: 600
     # 请求不可重复接收时间 10分钟
     repeat-interval: 600

+ 6 - 0
coffee-admin/src/main/resources/application.yml

@@ -75,3 +75,9 @@ aliyun:
     enable: true  # 是否开启阿里云物联网服务端订阅
   product:
     productKey: a1ALlsBa2ZK
+captcha:
+  enable: true
+  width: 140
+  height: 38
+  #验证码过期时间 5min
+  expire: 300

+ 2 - 0
coffee-common/src/main/java/com/coffee/common/dto/LoginDTO.java

@@ -21,4 +21,6 @@ public class LoginDTO {
     String mobile;
     String code;
 
+    String codeKey;
+
 }

+ 6 - 3
coffee-common/src/main/java/com/coffee/common/redis/RedisUtils.java

@@ -1,5 +1,6 @@
 package com.coffee.common.redis;
 
+import cn.hutool.core.collection.CollectionUtil;
 import org.redisson.api.RedissonClient;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
@@ -77,14 +78,16 @@ public class RedisUtils {
      * @param key 可以传一个值  或多个
      */
     @SuppressWarnings("unchecked")
-    public void del(String... key) {
+    public Boolean del(String... key) {
         if (key != null && key.length > 0) {
             if (key.length == 1) {
-                redisTemplate.delete(key[0]);
+                return redisTemplate.delete(key[0]);
             } else {
-                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
+                List<?> objects = CollectionUtils.arrayToList(key);
+                return  redisTemplate.delete((Collection<String>) objects)== CollectionUtil.size(objects);
             }
         }
+        return true;
     }
 
     //============================String=============================

+ 3 - 0
coffee-common/src/main/java/com/coffee/common/result/R.java

@@ -38,10 +38,13 @@ public class R<T> implements Serializable {
     @ApiModelProperty("返回错误消息")
     private String msg;
 
+    private Long timestamp;
+
     private R(int code, T data, String msg) {
         this.code = code;
         this.data = data;
         this.msg = msg;
+        this.timestamp=System.currentTimeMillis();
     }
 
     private R(IResultCode resultCode) {

+ 2 - 3
coffee-framework/src/main/java/com/coffee/framework/config/SaTokenConfig.java

@@ -32,7 +32,6 @@ public class SaTokenConfig {
     private static final List<String> IGNORE_URL = Lists.newArrayList();
 
     static {
-        IGNORE_URL.add("/**");
         IGNORE_URL.add("/index");
         IGNORE_URL.add("/login");
         IGNORE_URL.add("/logout");
@@ -43,9 +42,9 @@ public class SaTokenConfig {
         IGNORE_URL.add("/swagger-ui/**");
         IGNORE_URL.add("/v2/api-docs/*");
         IGNORE_URL.add("/v2/api-docs");
-
+        IGNORE_URL.add("/authority/captcha/**");
         IGNORE_URL.add("/system/curl/**");
-
+        IGNORE_URL.add("/system/sysConfig/getTime");
         IGNORE_URL.add("/system/sysDept/**");
     }
 

+ 1 - 1
coffee-framework/src/main/java/com/coffee/framework/web/exception/GlobalExceptionHandler.java

@@ -89,7 +89,7 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(RequestTimeOutException.class)
     public R businessException(RequestTimeOutException e) {
-        return R.result(ResultCode.TIME_ERROR, "请求已失效");
+        return R.result(ResultCode.TIME_ERROR, "时区错误");
     }
 
     /**

+ 20 - 0
coffee-framework/src/main/java/com/coffee/framework/web/service/impl/UserServiceImpl.java

@@ -1,5 +1,6 @@
 package com.coffee.framework.web.service.impl;
 
+import cn.dev33.satoken.spring.SpringMVCUtil;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.StrUtil;
@@ -23,12 +24,16 @@ import com.coffee.system.common.vo.*;
 import com.coffee.system.entity.SysMenu;
 import com.coffee.system.entity.SysRole;
 import com.coffee.system.entity.SysUser;
+import com.coffee.system.properties.CaptchaProperties;
 import com.coffee.system.service.ISysMenuService;
 import com.coffee.system.service.ISysRoleService;
 import com.coffee.system.service.ISysUserService;
+import com.coffee.system.utils.CaptchaTool;
 import com.google.common.collect.Sets;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.stereotype.Service;
+import org.springframework.web.bind.ServletRequestUtils;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 
@@ -44,11 +49,18 @@ import java.util.stream.Collectors;
  */
 @Slf4j
 @Service
+@EnableConfigurationProperties(CaptchaProperties.class)
 public class UserServiceImpl implements IUserService {
 
     @Resource
     private ISysMenuService sysMenuService;
 
+    @Resource
+    private CaptchaTool captchaTool;
+
+    @Resource
+    private CaptchaProperties captchaProperties;
+
     @Resource
     private ISysUserService sysUserService;
 
@@ -71,6 +83,14 @@ public class UserServiceImpl implements IUserService {
             if (StrUtil.isBlank(req.getPassword())) {
                 throw new CustomException("密码不能为空");
             }
+            if(captchaProperties.isEnable()){
+                HttpServletRequest request = SpringMVCUtil.getRequest();
+                String requestFrom = request.getHeader("RequestFrom");
+                //来自app的请求不需要验证码
+                if(!"TuoRenApp".equals(requestFrom)){
+                    captchaTool.ver(req.getCodeKey(),req.getCode());
+                }
+            }
             sysUser = sysUserService.getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getAccount, req.getUsername()));
             if (Objects.isNull(sysUser)) {
                 log.info("登录用户:{}不存在", req.getUsername());

+ 4 - 0
coffee-system/pom.xml

@@ -42,6 +42,10 @@
         </dependency>
 
 
+        <dependency>
+            <groupId>com.github.whvcse</groupId>
+            <artifactId>easy-captcha</artifactId>
+        </dependency>
 
 
     </dependencies>

+ 5 - 2
coffee-system/src/main/java/com/coffee/bus/hospital/his/strategy/all/MoreToLessHisStrategyHandler.java

@@ -63,10 +63,13 @@ public class MoreToLessHisStrategyHandler implements HisAllStrategyHandler {
             insert.addAll(source.subList(0,subSize));
             //新增临床信息
             for (int i = 0; i < insert.size(); i++) {
+                BusClinicEntity clinic = insert.get(i);
                 if(i!=0){
-                    insert.get(i).setFinished(true);
+                    //下一场手术的开始时间作为上一场手术的结束时间
+                    clinic.setEndTime(insert.get(i-1).getStartTime());
+                    clinic.setFinished(true);
                 }else {
-                    insert.get(i).setFinished(false);
+                    clinic.setFinished(false);
                 }
                 insert.get(i).setMonitorType(true);
             }

+ 0 - 1
coffee-system/src/main/java/com/coffee/bus/web/handler/CheckSignHandler.java

@@ -7,7 +7,6 @@ import com.coffee.bus.web.RequestCheckProperties;
 import com.coffee.common.exception.RequestSignErrorException;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.annotation.Order;

+ 2 - 4
coffee-system/src/main/java/com/coffee/bus/web/handler/CheckTimeHandler.java

@@ -38,11 +38,9 @@ public class CheckTimeHandler implements HandlerInterceptor {
         if (method.equals(HttpMethod.POST.name())&&properties.getExpireInterval()!=null) {
             Long timestamp = Value.simple(request.getHeader("Timestamp")).asLong();
             long now = System.currentTimeMillis();
-            if(timestamp>now){
-                response.getOutputStream().write(JSONUtil.parse(R.result(ResultCode.TIME_ERROR,"时区错误")).toString().getBytes());
-            }
+            //时间间隔不超10分钟
             long subTime = TimeUnit.MILLISECONDS
-                    .toSeconds(now - timestamp);
+                    .toSeconds(Math.abs(Math.subtractExact(timestamp,now)));
             if(subTime>properties.getExpireInterval()){
                 throw new RequestTimeOutException();
             }

+ 7 - 4
coffee-system/src/main/java/com/coffee/bus/websocket/DefaultWsServerAioListener.java

@@ -1,11 +1,11 @@
 package com.coffee.bus.websocket;
 
 import com.coffee.common.config.websocket.handler.WsHandler;
+import io.netty.util.concurrent.DefaultEventExecutor;
+import io.netty.util.concurrent.EventExecutorGroup;
 import lombok.extern.slf4j.Slf4j;
 import org.tio.core.ChannelContext;
 import org.tio.core.intf.Packet;
-import org.tio.server.intf.ServerAioListener;
-import org.tio.websocket.common.WsSessionContext;
 import org.tio.websocket.server.WsServerAioListener;
 
 import java.util.*;
@@ -31,7 +31,7 @@ public class DefaultWsServerAioListener extends WsServerAioListener {
     public boolean onHeartbeatTimeout(ChannelContext channelContext, Long interval, int heartbeatTimeoutCount) {
         //连接关闭时进行业务处理
         log.info("{},心跳超时,通道关闭", channelContext);
-        wsHandlers.forEach(wsHandler -> wsHandler.close(channelContext));
+        wsHandlers.parallelStream().forEach(wsHandler -> wsHandler.close(channelContext));
         return false;
     }
 
@@ -57,6 +57,9 @@ public class DefaultWsServerAioListener extends WsServerAioListener {
 
     @Override
     public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String remark, boolean isRemove) throws Exception {
-
+        if(log.isDebugEnabled()){
+            log.debug("{},通道关闭", channelContext);
+        }
+        wsHandlers.parallelStream().forEach(wsHandler -> wsHandler.close(channelContext));
     }
 }

+ 50 - 0
coffee-system/src/main/java/com/coffee/system/controller/SysCaptchaController.java

@@ -0,0 +1,50 @@
+package com.coffee.system.controller;
+
+import com.coffee.common.exception.CustomException;
+import com.coffee.system.properties.CaptchaProperties;
+import com.coffee.system.utils.CaptchaTool;
+import com.wf.captcha.ArithmeticCaptcha;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName SysCaptchaController.java
+ * @Description 验证码控制器
+ * @createTime 2022年06月11日 09:14:00
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/authority/captcha")
+@Api(tags = "获取验证码",value = "【无权限】")
+@Slf4j
+public class SysCaptchaController {
+    private final CaptchaTool captchaTool;
+
+    private final CaptchaProperties captchaProperties;
+
+    @GetMapping
+    @ApiOperation("获取验证码")
+    public void get(@RequestParam("key")String key, HttpServletRequest request, HttpServletResponse response){
+        // 算术类型
+        ArithmeticCaptcha captcha = new ArithmeticCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());
+        try {
+            captchaTool.out(key,captcha,captchaProperties.getExpire(),request,response);
+        } catch (IOException e) {
+            log.error("生成验证码失败,",e);
+            throw new CustomException("系统繁忙,请稍后再试");
+        }
+    }
+}

+ 22 - 0
coffee-system/src/main/java/com/coffee/system/properties/CaptchaProperties.java

@@ -0,0 +1,22 @@
+package com.coffee.system.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName CaptchaProperties.java
+ * @Description TODO
+ * @createTime 2022年06月10日 10:31:00
+ */
+@ConfigurationProperties("captcha")
+@Data
+@Configuration
+public class CaptchaProperties {
+    private boolean enable;
+    private int width;
+    private int height;
+    private int expire;
+}

+ 59 - 0
coffee-system/src/main/java/com/coffee/system/utils/CaptchaTool.java

@@ -0,0 +1,59 @@
+package com.coffee.system.utils;
+
+import cn.hutool.core.util.StrUtil;
+import com.coffee.common.exception.CustomException;
+import com.coffee.common.redis.RedisUtils;
+import com.wf.captcha.base.Captcha;
+import com.wf.captcha.utils.CaptchaUtil;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName CaptchaTool.java
+ * @Description TODO
+ * @createTime 2022年06月10日 09:59:00
+ */
+@Component
+@AllArgsConstructor
+public class CaptchaTool {
+    private final RedisUtils redisUtils;
+
+    /**
+     * 输出验证码
+     * @param key
+     * @param captcha  Captcha
+     * @param request  HttpServletRequest
+     * @param response HttpServletResponse
+     * @throws IOException IO异常
+     */
+    public void out(String key,Captcha captcha, int expire,HttpServletRequest request, HttpServletResponse response)
+            throws IOException {
+        CaptchaUtil.setHeader(response);
+        //验证码放入缓存30分钟
+        redisUtils.set(key,captcha.text().toLowerCase(), expire);
+        captcha.out(response.getOutputStream());
+    }
+
+
+    public boolean ver(String key,String code){
+        if(StrUtil.isBlank(code)){
+            throw new CustomException("验证码不能为空");
+        }
+        Object cacheCode = redisUtils.get(key);
+        if (Objects.nonNull(cacheCode)) {
+            if (Objects.equals(cacheCode,code)) {
+                return Boolean.TRUE.equals(redisUtils.del(key));
+            }
+            throw new CustomException("验证码错误");
+        }
+        throw new CustomException("验证码已失效");
+    }
+}

+ 8 - 0
pom.xml

@@ -38,6 +38,7 @@
         <jython.version>2.7.1</jython.version>
         <knife4j.version>2.0.7</knife4j.version>
         <redisson.version>3.17.0</redisson.version>
+        <captcha.version>1.6.2</captcha.version>
     </properties>
 
     <modules>
@@ -229,6 +230,13 @@
                 </exclusions>
             </dependency>
 
+            <!--验证码配置-->
+            <dependency>
+                <groupId>com.github.whvcse</groupId>
+                <artifactId>easy-captcha</artifactId>
+                <version>${captcha.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>