فهرست منبع

重构,讲commonweb抽出

dengsixing 3 سال پیش
والد
کامیت
440816436e
35فایلهای تغییر یافته به همراه2161 افزوده شده و 0 حذف شده
  1. 162 0
      4dkankan-common-web/pom.xml
  2. 54 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/aop/FeignInterceptor.java
  3. 111 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/aop/VisitLogInterceptor.java
  4. 29 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/bean/DownLoadProgressBean.java
  5. 29 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/bean/DownLoadTaskBean.java
  6. 108 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/config/FileRouteConfig.java
  7. 36 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/config/LogPathHostNameProperty.java
  8. 8 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/config/RedisDefaultConfig.java
  9. 44 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/config/ResultStatusDecoder.java
  10. 155 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/config/SentinelFileDataSourceInitFunc.java
  11. 57 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/config/SentinelUrlBlockHandler.java
  12. 110 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/config/ShiroConfig.java
  13. 40 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/config/ShiroModularRealmAuthenticator.java
  14. 23 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/config/SupportAutoConfiguration.java
  15. 50 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/constant/CameraTypeEnum.java
  16. 26 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/constant/FilterConstant.java
  17. 78 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/controller/BaseController.java
  18. 50 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/controller/CustomErrorController.java
  19. 138 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/exception/GlobalExceptionHandler.java
  20. 34 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/exception/JwtAuthenticationException.java
  21. 10 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/factory/LogFactory.java
  22. 113 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/jwt/JwtFilter.java
  23. 33 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/jwt/JwtToken.java
  24. 37 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/model/SSOUser.java
  25. 60 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/realm/AgentJwtRealm.java
  26. 62 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/realm/AppJwtRealm.java
  27. 61 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/realm/ManagerJwtRealm.java
  28. 90 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/realm/UserJwtRealm.java
  29. 54 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/response/BaseResponseAdvice.java
  30. 73 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/user/SSOLoginHelper.java
  31. 97 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/user/SSOLoginStore.java
  32. 27 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/user/SSOUser.java
  33. 21 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/util/SsoUtil.java
  34. 35 0
      4dkankan-common-web/src/main/java/com/fdkankan/web/util/WebUtil.java
  35. 46 0
      pom.xml

+ 162 - 0
4dkankan-common-web/pom.xml

@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>4dkankan-utils</artifactId>
+    <groupId>com.fdkankan</groupId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>4dkankan-common-web</artifactId>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>com.fdkankan</groupId>
+      <artifactId>4dkankan-common-utils</artifactId>
+      <version>ZJ-2.0.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+    </dependency>
+
+<!--    <dependency>-->
+<!--      <groupId>cn.hutool</groupId>-->
+<!--      <artifactId>hutool-all</artifactId>-->
+<!--    </dependency>-->
+
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-webflux</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.alibaba</groupId>
+      <artifactId>fastjson</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.shiro</groupId>
+      <artifactId>shiro-spring</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>net.coobird</groupId>
+      <artifactId>thumbnailator</artifactId>
+      <version>0.4.8</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>2.8.5</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.fdkankan</groupId>
+      <artifactId>4dkankan-utils-redis</artifactId>
+      <version>2.0.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.alibaba.cloud</groupId>
+      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.alibaba.cloud</groupId>
+      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.poi</groupId>
+      <artifactId>poi</artifactId>
+      <version>3.8</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.poi</groupId>
+      <artifactId>poi-ooxml</artifactId>
+      <version>3.8</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.junit.vintage</groupId>
+          <artifactId>junit-vintage-engine</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.plugin</groupId>
+      <artifactId>spring-plugin-core</artifactId>
+      <version>1.2.0.RELEASE</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.plugin</groupId>
+      <artifactId>spring-plugin-metadata</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-aop</artifactId>
+    </dependency>
+    <!--        <dependency>-->
+    <!--            <groupId>com.alibaba.cloud</groupId>-->
+    <!--            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>-->
+    <!--        </dependency>-->
+
+    <dependency>
+      <groupId>com.baomidou</groupId>
+      <artifactId>mybatis-plus-extension</artifactId>
+      <version>3.4.3.4</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-validation</artifactId>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+    </plugins>
+
+  </build>
+
+
+</project>

+ 54 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/aop/FeignInterceptor.java

@@ -0,0 +1,54 @@
+//
+//import com.alibaba.fastjson.JSON;
+//import com.fdkankan.common.constant.LogFormatConstant;
+//import java.util.Enumeration;
+//import javax.servlet.http.HttpServletRequest;
+//import lombok.extern.slf4j.Slf4j;
+//import org.aspectj.lang.ProceedingJoinPoint;
+//import org.aspectj.lang.annotation.Around;
+//import org.aspectj.lang.annotation.Aspect;
+//import org.aspectj.lang.annotation.Pointcut;
+//import org.aspectj.lang.reflect.MethodSignature;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//import org.springframework.stereotype.Component;
+//import org.springframework.web.context.request.RequestContextHolder;
+//import org.springframework.web.context.request.ServletRequestAttributes;
+//
+//@Component
+//@Aspect
+//@Slf4j
+//public class FeignInterceptor {
+//
+//	// 切入点表达式
+//	@Pointcut("execution(* com.fdkankan.*.feign..*.*(..))")
+//	public void privilege() {
+//	}
+//
+//	@Around("privilege()")
+//	public Object around(ProceedingJoinPoint pjp) throws Throwable {
+//
+//		// 获取类名
+//		String className = pjp.getTarget().getClass().getName();
+//		// 获取执行的方法名称
+//		String methodName = pjp.getSignature().getName();
+//		// 获取参数名称
+//		String[] parameterNamesArgs = ((MethodSignature) pjp.getSignature()).getParameterNames();
+//		// 定义返回参数
+//		Object result = null;
+//		// 获取方法参数
+//		Object[] args = pjp.getArgs();
+//		StringBuilder params = new StringBuilder();
+//		for(int i = 0; i < parameterNamesArgs.length; i++){
+//			params.append(",").append(parameterNamesArgs[i]).append("=").append(args[i]);
+//		}
+//		log.info(LogFormatConstant.FEIGN_LOG_START, className, methodName, params.substring(1));
+//		// 执行目标方法
+//		result = pjp.proceed();
+//
+//		log.info(LogFormatConstant.FEIGN_LOG_END, className, methodName, JSON.toJSONString(result));
+//
+//		return result;
+//	}
+//}
+//

+ 111 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/aop/VisitLogInterceptor.java

@@ -0,0 +1,111 @@
+//
+//import com.fdkankan.common.constant.LogFormatConstant;
+//import com.fdkankan.common.factory.LogFactory;
+//import java.util.Enumeration;
+//import javax.servlet.http.HttpServletRequest;
+//import lombok.extern.slf4j.Slf4j;
+//import org.aspectj.lang.ProceedingJoinPoint;
+//import org.aspectj.lang.annotation.Around;
+//import org.aspectj.lang.annotation.Aspect;
+//import org.aspectj.lang.annotation.Pointcut;
+//import org.aspectj.lang.reflect.MethodSignature;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//import org.springframework.stereotype.Component;
+//import org.springframework.web.context.request.RequestContextHolder;
+//import org.springframework.web.context.request.ServletRequestAttributes;
+//
+//@Component
+//@Aspect
+//@Slf4j
+//public class VisitLogInterceptor {
+//
+//	// 切入点表达式
+//	@Pointcut("execution(public * com.fdkankan.*..controller..*.*(..))")
+//	public void privilege() {
+//	}
+//
+//	@Around("privilege()")
+//	public Object around(ProceedingJoinPoint pjp) throws Throwable {
+//
+//		// 获取类名
+//		String className = pjp.getTarget().getClass().getName();// pjp.getTarget().getClass().getSimpleName();
+//		// 获取执行的方法名称
+//		String methodName = pjp.getSignature().getName();
+//		// 获取参数名称
+//		String[] parameterNamesArgs = ((MethodSignature) pjp.getSignature()).getParameterNames();
+//		// 定义返回参数
+//		Object result = null;
+//		// 获取方法参数
+//		Object[] args = pjp.getArgs();
+//		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+//		// 请求的URL
+//		String requestURL = request.getRequestURL().toString();
+//		String ip = getIpAddr(request);
+//
+//		StringBuffer paramsBuf = new StringBuffer();
+//		// 获取请求参数集合并进行遍历拼接
+//		for (int i = 0; i < args.length; i++) {
+//			if (paramsBuf.length() > 0) {
+//				paramsBuf.append("|");
+//			}
+//			paramsBuf.append(parameterNamesArgs[i]).append(" = ").append(args[i]);
+//		}
+//		StringBuffer headerBuf = new StringBuffer();
+//		Enumeration<String> headerNames = request.getHeaderNames();
+//		while (headerNames.hasMoreElements()) {
+//			String key = (String) headerNames.nextElement();
+//			String value = request.getHeader(key);
+//			if (headerBuf.length() > 0) {
+//				headerBuf.append("|");
+//			}
+//			headerBuf.append(key).append("=").append(value);
+//		}
+//
+//		// 打印请求参数参数
+//		// 记录开始时间
+//		long start = System.currentTimeMillis();
+//
+//		log.info(LogFormatConstant.REQUEST_LOG_START, ip, requestURL, className, methodName, paramsBuf.toString(), headerBuf.toString());
+//
+//		// 执行目标方法
+//		result = pjp.proceed();
+//
+//		// 获取执行完的时间 打印返回报文
+//		log.info(LogFormatConstant.REQUEST_LOG_END, requestURL, className, methodName, result, (System.currentTimeMillis() - start));
+//		return result;
+//	}
+//
+//	/**
+//	 * @Title: getIpAddr
+//	 * @Description: 获取ip
+//	 * @param request
+//	 * @return
+//	 * @return String 返回类型
+//	 */
+//	public String getIpAddr(HttpServletRequest request) {
+//		String ipAddress = null;
+//		ipAddress = request.getHeader("x-forwarded-for");
+//		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+//			ipAddress = request.getHeader("Proxy-Client-IP");
+//		}
+//		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+//			ipAddress = request.getHeader("WL-Proxy-Client-IP");
+//		}
+//		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+//			ipAddress = request.getRemoteAddr();
+//		}
+//
+//		//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
+//		if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
+//			// = 15
+//			if (ipAddress.indexOf(",") > 0) {
+//				ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
+//			}
+//		}
+//		// 或者这样也行,对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
+//		//return ipAddress!=null&&!"".equals(ipAddress)?ipAddress.split(",")[0]:null;
+//		return ipAddress;
+//	}
+//}
+//

+ 29 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/bean/DownLoadProgressBean.java

@@ -0,0 +1,29 @@
+package com.fdkankan.web.bean;
+
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>
+ * 场景下载进度
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/22
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DownLoadProgressBean implements Serializable {
+
+    private String url;
+
+    private Integer percent;
+
+    private Integer status;
+
+}

+ 29 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/bean/DownLoadTaskBean.java

@@ -0,0 +1,29 @@
+package com.fdkankan.web.bean;
+
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/22
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DownLoadTaskBean implements Serializable {
+
+    private Long userId;
+
+    private String num;
+
+    private String type;
+
+}

+ 108 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/config/FileRouteConfig.java

@@ -0,0 +1,108 @@
+package com.fdkankan.web.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+
+@Component
+@ConfigurationProperties(prefix = "file.route")
+public class FileRouteConfig {
+    /**
+     * 路径
+     */
+    //保存硬盘地址
+    private String hardDisk;
+	//保存硬盘地址(激光相机)
+	private String hardDiskLaser;
+    //默认图片类型文件夹
+    private String imageFolder;
+    //默认文件类型文件夹
+    private String documentFolder;
+    //默认的视频类型文件夹
+    private String videoFolder;
+    //默认的音频类型文件夹
+    private String musicFolder;
+    //允许上传的ip(上传白名单)
+    private String[] IPs;
+    /**
+     * 类型
+     */
+    //图片类型
+    private String[] imageType;
+    //文件类型
+    private String[] documentType;
+    //视频类型
+    private String[] videoType;
+    //音频类型
+    private String[] musicType;
+	public String getHardDisk() {
+		return hardDisk;
+	}
+	public String getHardDiskLaser() {
+		return hardDiskLaser;
+	}
+	public String getImageFolder() {
+		return imageFolder;
+	}
+	public String getDocumentFolder() {
+		return documentFolder;
+	}
+	public String getVideoFolder() {
+		return videoFolder;
+	}
+	public String getMusicFolder() {
+		return musicFolder;
+	}
+	public String[] getIPs() {
+		return IPs;
+	}
+	public String[] getImageType() {
+		return imageType;
+	}
+	public String[] getDocumentType() {
+		return documentType;
+	}
+	public String[] getVideoType() {
+		return videoType;
+	}
+	public String[] getMusicType() {
+		return musicType;
+	}
+	public void setHardDisk(String hardDisk) {
+
+		this.hardDisk = hardDisk;
+	}
+	public void setHardDiskLaser(String hardDiskLaser) {
+
+		this.hardDiskLaser = hardDiskLaser;
+	}
+	public void setImageFolder(String imageFolder) {
+		this.imageFolder = imageFolder;
+	}
+	public void setDocumentFolder(String documentFolder) {
+		this.documentFolder = documentFolder;
+	}
+	public void setVideoFolder(String videoFolder) {
+		this.videoFolder = videoFolder;
+	}
+	public void setMusicFolder(String musicFolder) {
+		this.musicFolder = musicFolder;
+	}
+	public void setIPs(String[] iPs) {
+		IPs = iPs;
+	}
+	public void setImageType(String[] imageType) {
+		this.imageType = imageType;
+	}
+	public void setDocumentType(String[] documentType) {
+		this.documentType = documentType;
+	}
+	public void setVideoType(String[] videoType) {
+		this.videoType = videoType;
+	}
+	public void setMusicType(String[] musicType) {
+		this.musicType = musicType;
+	}
+    
+    
+}

+ 36 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/config/LogPathHostNameProperty.java

@@ -0,0 +1,36 @@
+package com.fdkankan.web.config;
+
+import ch.qos.logback.core.PropertyDefinerBase;
+import com.fdkankan.common.util.FileUtils;
+import org.springframework.util.ObjectUtils;
+
+//@Component
+public class LogPathHostNameProperty extends PropertyDefinerBase {
+
+//    @Value("${hostName.filePath:/opt/hosts/hosts.txt}")
+//    private String hostNamePath;
+
+    @Override
+    public String getPropertyValue() {
+
+        String hostNamePath = getContext().getProperty("hostName.filePath");
+        if(ObjectUtils.isEmpty(hostNamePath)){
+            hostNamePath = "/opt/hosts/hosts.txt";
+        }
+        String hostName = "null";
+        try {
+            hostName = FileUtils.readFile(hostNamePath);
+            // 去除空格
+            if(!ObjectUtils.isEmpty(hostName)){
+                hostName = hostName.trim().replaceAll("\\s","");
+            }
+        } catch (Exception e) {
+            System.err.println("=========================error======================");
+            System.err.println("从文件中获取服务器名称失败,文件路径:"+hostNamePath);
+            return hostName;
+        }
+        return hostName;
+    }
+
+
+}

+ 8 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/config/RedisDefaultConfig.java

@@ -0,0 +1,8 @@
+package com.fdkankan.web.config;
+
+public class RedisDefaultConfig {
+//    public static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS; //redis默认过期时间单位
+//    public static final int DEFAULT_EXPIRE_TIME = 7200;  // redis默认过期时间,单位/秒, 60*60*2=2H, 两小时
+//    public static final int CAMERA_EXPIRE_TIME = 604800;  // 相机登陆7天有效期
+//    public static final int USER_EXPIRE_TIME = 21600;  // agent用户有效期
+}

+ 44 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/config/ResultStatusDecoder.java

@@ -0,0 +1,44 @@
+//package common.config;
+//
+//import com.alibaba.cloud.commons.io.IOUtils;
+//import com.alibaba.fastjson.JSONObject;
+//import com.fdkankan.common.constant.ServerCode;
+//import com.fdkankan.common.exception.BusinessException;
+//import com.fdkankan.common.response.ResultData;
+//import feign.Response;
+//import feign.codec.Decoder;
+//import lombok.extern.slf4j.Slf4j;
+//
+//import java.io.IOException;
+//import java.lang.reflect.Type;
+//import java.nio.charset.StandardCharsets;
+//import java.util.Objects;
+//
+//@Slf4j
+//public final class ResultStatusDecoder implements Decoder {
+//
+//    public static final String CONTENT_KEY = "content";
+//    final Decoder delegate;
+//
+//    public ResultStatusDecoder(Decoder delegate) {
+//        Objects.requireNonNull(delegate, "Decoder must not be null. ");
+//        this.delegate = delegate;
+//    }
+//
+//    @Override
+//    public Object decode(Response response, Type type) throws IOException {
+//        // 判断是否返回参数是否是异常
+//        String resultStr = IOUtils.toString(response.body().asInputStream(), StandardCharsets.UTF_8);
+//        log.info("feign调用返回,result msg ->{}",resultStr);
+//        try {
+//            ResultData resultData = JSONObject.parseObject(resultStr, ResultData.class);
+//            if(resultData.getCode() != ServerCode.SUCCESS.code()){
+//                throw new BusinessException(resultData.getCode(),resultData.getMessage());
+//            }
+//        }catch (Exception e){
+//            e.printStackTrace();
+//        }
+//        // 回写body
+//        return delegate.decode(response.toBuilder().body(resultStr, StandardCharsets.UTF_8).build(), type);
+//    }
+//}

+ 155 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/config/SentinelFileDataSourceInitFunc.java

@@ -0,0 +1,155 @@
+//
+//import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
+//import com.alibaba.csp.sentinel.datasource.*;
+//import com.alibaba.csp.sentinel.init.InitFunc;
+//import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
+//import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
+//import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
+//import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
+//import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+//import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+//import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
+//import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
+//import com.alibaba.csp.sentinel.slots.system.SystemRule;
+//import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
+//import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
+//import com.alibaba.fastjson.JSON;
+//import com.alibaba.fastjson.TypeReference;
+//
+//import java.io.File;
+//import java.io.IOException;
+//import java.util.List;
+//
+///**
+// * <p>
+// * sentinel规则数据持久化到本地文件
+// * </p>
+// *
+// * @author dengsixing
+// * @since 2022/1/26
+// **/
+//public class SentinelFileDataSourceInitFunc implements InitFunc {
+//
+//    @Override
+//    public void init() throws Exception {
+//        //持久化在本地的目录
+//        String ruleDir = System.getProperty("user.home") + "/sentinel/rules";
+//        String flowRulePath = ruleDir + "/flow-rule.json";
+//        String degradeRulePath = ruleDir + "/degrade-rule.json";
+//        String systemRulePath = ruleDir + "/system-rule.json";
+//        String authorityRulePath = ruleDir + "/authority-rule.json";
+//        String paramFlowRulePath = ruleDir + "/param-flow-rule.json";
+//
+//        this.mkdirIfNotExits(ruleDir);
+//        this.createFileIfNotExits(flowRulePath);
+//        this.createFileIfNotExits(degradeRulePath);
+//        this.createFileIfNotExits(systemRulePath);
+//        this.createFileIfNotExits(authorityRulePath);
+//        this.createFileIfNotExits(paramFlowRulePath);
+//
+//        // 流控规则
+//        ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(
+//                flowRulePath,
+//                flowRuleListParser
+//        );
+//        // 将可读数据源注册至FlowRuleManager
+//        // 这样当规则文件发生变化时,就会更新规则到内存
+//        FlowRuleManager.register2Property(flowRuleRDS.getProperty());
+//        WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<List<FlowRule>>(
+//                flowRulePath,
+//                this::encodeJson
+//        );
+//        // 将可写数据源注册至transport模块的WritableDataSourceRegistry中
+//        // 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写入到文件中
+//        WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
+//
+//        // 降级规则
+//        ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(
+//                degradeRulePath,
+//                degradeRuleListParser
+//        );
+//        DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
+//        WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(
+//                degradeRulePath,
+//                this::encodeJson
+//        );
+//        WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);
+//
+//        // 系统规则
+//        ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(
+//                systemRulePath,
+//                systemRuleListParser
+//        );
+//        SystemRuleManager.register2Property(systemRuleRDS.getProperty());
+//        WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(
+//                systemRulePath,
+//                this::encodeJson
+//        );
+//        WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
+//
+//        // 授权规则
+//        ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(
+//                flowRulePath,
+//                authorityRuleListParser
+//        );
+//        AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
+//        WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(
+//                authorityRulePath,
+//                this::encodeJson
+//        );
+//        WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
+//
+//        // 热点参数规则
+//        ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
+//                paramFlowRulePath,
+//                paramFlowRuleListParser
+//        );
+//        ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
+//        WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(
+//                paramFlowRulePath,
+//                this::encodeJson
+//        );
+//        ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
+//    }
+//
+//    private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(
+//            source,
+//            new TypeReference<List<FlowRule>>() {}
+//    );
+//    private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(
+//            source,
+//            new TypeReference<List<DegradeRule>>() {}
+//    );
+//    private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(
+//            source,
+//            new TypeReference<List<SystemRule>>() {}
+//    );
+//
+//    private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(
+//            source,
+//            new TypeReference<List<AuthorityRule>>() {}
+//    );
+//
+//    private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject(
+//            source,
+//            new TypeReference<List<ParamFlowRule>>() {}
+//    );
+//
+//    private void mkdirIfNotExits(String filePath) throws IOException {
+//        File file = new File(filePath);
+//        if (!file.exists()) {
+//            file.mkdirs();
+//        }
+//    }
+//
+//    private void createFileIfNotExits(String filePath) throws IOException {
+//        File file = new File(filePath);
+//        if (!file.exists()) {
+//            file.createNewFile();
+//        }
+//    }
+//
+//    private <T> String encodeJson(T t) {
+//        return JSON.toJSONString(t);
+//    }
+//}

+ 57 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/config/SentinelUrlBlockHandler.java

@@ -0,0 +1,57 @@
+//package com.fdkankan.web.config;
+//
+//import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
+//import com.alibaba.csp.sentinel.slots.block.BlockException;
+//import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
+//import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
+//import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+//import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
+//import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
+//import com.fasterxml.jackson.databind.ObjectMapper;
+//import com.fdkankan.common.response.ResultData;
+//import lombok.extern.slf4j.Slf4j;
+//import org.springframework.http.MediaType;
+//import org.springframework.stereotype.Component;
+//
+//import javax.servlet.http.HttpServletRequest;
+//import javax.servlet.http.HttpServletResponse;
+//import java.io.IOException;
+//
+///**
+// * <p>
+// * sentinel统一异常处理
+// * </p>
+// *
+// * @author dengsixing
+// * @since 2022/1/26
+// **/
+//@Slf4j
+//@Component
+//public class SentinelUrlBlockHandler implements BlockExceptionHandler {
+//    @Override
+//    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
+//        String msg = null;
+//        if (e instanceof FlowException) {
+//            msg = "限流了";
+//        } else if (e instanceof DegradeException) {
+//            msg = "降级了";
+//        } else if (e instanceof ParamFlowException) {
+//            msg = "热点参数限流";
+//        } else if (e instanceof SystemBlockException) {
+//            msg = "系统规则(负载/...不满足要求)";
+//        } else if (e instanceof AuthorityException) {
+//            msg = "授权规则不通过";
+//        }
+//        // http状态码
+//        response.setStatus(500);
+//        response.setCharacterEncoding("utf-8");
+//        response.setHeader("Content-Type", "application/json;charset=utf-8");
+//        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+//
+//        new ObjectMapper()
+//                .writeValue(
+//                        response.getWriter(),
+//                        ResultData.error(-1, msg)
+//                );
+//    }
+//}

+ 110 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/config/ShiroConfig.java

@@ -0,0 +1,110 @@
+package com.fdkankan.web.config;
+
+import com.fdkankan.common.constant.LoginType;
+import com.fdkankan.web.realm.AppJwtRealm;
+import com.fdkankan.web.realm.ManagerJwtRealm;
+import com.fdkankan.web.realm.UserJwtRealm;
+import com.fdkankan.web.constant.FilterConstant;
+import com.fdkankan.web.jwt.JwtFilter;
+import com.fdkankan.web.realm.AgentJwtRealm;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import javax.servlet.Filter;
+import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
+import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
+import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
+import org.apache.shiro.mgt.DefaultSubjectDAO;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.realm.Realm;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ShiroConfig {
+
+    @Autowired
+    ModularRealmAuthenticator modularRealmAuthenticator;
+    @Autowired
+    private UserJwtRealm userJwtRealm;
+    @Autowired
+    private AgentJwtRealm agentJwtRealm;
+    @Autowired
+    private ManagerJwtRealm managerJwtRealm;
+    @Autowired
+    private AppJwtRealm appJwtRealm;
+
+    @Bean("shiroFilter")
+    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
+         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
+        shiroFilterFactoryBean.setSecurityManager(securityManager);
+        //拦截器
+        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
+        // 配置不会被拦截的链接 顺序判断
+//        filterChainDefinitionMap.put("/**", "anon");
+
+        // 添加自己的过滤器并且取名为jwt
+        Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
+        filterMap.put("user_jwt", new JwtFilter(LoginType.USER.code()));
+        filterMap.put("manager_jwt", new JwtFilter(LoginType.MANAGER.code()));
+        filterMap.put("agent_jwt", new JwtFilter(LoginType.AGENT.code()));
+        filterMap.put("app_jwt", new JwtFilter(LoginType.APP.code()));
+        shiroFilterFactoryBean.setFilters(filterMap);
+        //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边
+        filterChainDefinitionMap.put(FilterConstant.FILTER_USER_URL + "/**", "user_jwt");
+        filterChainDefinitionMap.put(FilterConstant.FILTER_SCENE_URL + "/**", "user_jwt");
+        filterChainDefinitionMap.put(FilterConstant.FILTER_DEVICE_URL + "/**", "user_jwt");
+        filterChainDefinitionMap.put(FilterConstant.FILTER_PAY_URL + "/**", "user_jwt");
+        filterChainDefinitionMap.put(FilterConstant.FILTER_MANAGER_URL + "/**", "manager_jwt");
+        filterChainDefinitionMap.put(FilterConstant.FILTER_AGENT_URL + "/**", "agent_jwt");
+        filterChainDefinitionMap.put(FilterConstant.FILTER_APP_URL + "/**", "app_jwt");
+        //未授权界面;
+        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
+        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
+
+        return shiroFilterFactoryBean;
+    }
+
+    @Bean("securityManager")
+    public SecurityManager securityManager() {
+        List<Realm> realms = new ArrayList<>();
+        realms.add(userJwtRealm);
+        realms.add(agentJwtRealm);
+        realms.add(managerJwtRealm);
+        realms.add(appJwtRealm);
+
+        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+        //设置realm.
+        securityManager.setAuthenticator(modularRealmAuthenticator);
+        securityManager.setRealms(realms);
+        /*
+         * 关闭shiro自带的session,详情见文档
+         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
+         */
+        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
+        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
+        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
+        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
+        securityManager.setSubjectDAO(subjectDAO);
+
+        return securityManager;
+    }
+
+    @Bean
+    public ModularRealmAuthenticator modularRealmAuthenticator(){
+        //自己重写的ShiroModularRealmAuthenticator
+        ShiroModularRealmAuthenticator modularRealmAuthenticator = new ShiroModularRealmAuthenticator();
+        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
+        return modularRealmAuthenticator;
+    }
+
+
+
+
+
+}

+ 40 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/config/ShiroModularRealmAuthenticator.java

@@ -0,0 +1,40 @@
+package com.fdkankan.web.config;
+
+import com.fdkankan.web.jwt.JwtToken;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
+import org.apache.shiro.realm.Realm;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class ShiroModularRealmAuthenticator extends ModularRealmAuthenticator {
+
+    @Override
+    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)
+            throws AuthenticationException {
+        // 判断getRealms()是否返回为空
+        assertRealmsConfigured();
+        // 强制转换回自定义的CustomizedToken
+        JwtToken customizedToken = (JwtToken) authenticationToken;
+        // 登录类型
+        String loginType = customizedToken.getLoginType();
+        // 所有Realm
+        Collection<Realm> realms = getRealms();
+        // 登录类型对应的所有Realm
+        Collection<Realm> typeRealms = new ArrayList<>();
+        for (Realm realm : realms) {
+            if (realm.getName().contains(loginType))
+                typeRealms.add(realm);
+        }
+
+        // 判断是单Realm还是多Realm
+        if (typeRealms.size() == 1)
+            return doSingleRealmAuthentication(typeRealms.iterator().next(), customizedToken);
+        else
+            return doMultiRealmAuthentication(typeRealms, customizedToken);
+    }
+
+}

+ 23 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/config/SupportAutoConfiguration.java

@@ -0,0 +1,23 @@
+//package common.config;
+//
+//
+//import feign.codec.Decoder;
+//import feign.optionals.OptionalDecoder;
+//import org.springframework.beans.factory.ObjectFactory;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
+//import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
+//import org.springframework.cloud.openfeign.support.SpringDecoder;
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//
+//@Configuration
+//public class SupportAutoConfiguration {
+//    @Autowired
+//    private ObjectFactory<HttpMessageConverters> messageConverters;
+//
+//    @Bean
+//    public Decoder feignDecoder() {
+//        return new ResultStatusDecoder(new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))));
+//    }
+//}

+ 50 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/constant/CameraTypeEnum.java

@@ -0,0 +1,50 @@
+package com.fdkankan.web.constant;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum CameraTypeEnum {
+    DOUBLE_EYE(0,"KK-","4DKKLITE_","旧双目相机"),
+    FDKK_PRO(1,"KK-","4DKKPRO_","四维看看pro八目相机"),
+    FDKK_LITE(2,"KK-","4DKKLITE_","四维看看lite"),
+    ZHIHOUSE_REDHOUSE(5,"KK-","4DKKLITE_","指房宝小红屋相机"),
+    DOUBLE_EYE_TURN(9,"KJ-","4DKKLITE_","双目转台"),
+    LASER_TURN(10,"SS-","4DKKLA_","激光转台");
+
+
+    private int type;
+    private String sceneNumPrefix;
+    private String wifiNamePrefix;
+    private String desc;
+
+    public int getType() {
+        return type;
+    }
+
+    public String getSceneNumPrefix() {
+        return sceneNumPrefix;
+    }
+
+    static Map<Integer,CameraTypeEnum> typeMaps = new HashMap<>(5);
+
+    static{
+        for (CameraTypeEnum typeEnum : CameraTypeEnum.values()) {
+            typeMaps.put(typeEnum.getType(),typeEnum);
+        }
+    }
+
+    CameraTypeEnum(Integer type, String sceneNumPrefix, String wifiNamePrefix, String desc) {
+        this.type = type;
+        this.sceneNumPrefix = sceneNumPrefix;
+        this.wifiNamePrefix = wifiNamePrefix;
+        this.desc = desc;
+    }
+
+    public static String getSceneNumPrefixByType(Integer type){
+        if(typeMaps.containsKey(type)){
+            return typeMaps.get(type).getSceneNumPrefix();
+        }
+        return "";
+    }
+
+}

+ 26 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/constant/FilterConstant.java

@@ -0,0 +1,26 @@
+package com.fdkankan.web.constant;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FilterConstant {
+
+    public static final String FILTER_USER_URL = "/service/user";
+    public static final String FILTER_SCENE_URL = "/service/scene/edit";
+    public static final String FILTER_DEVICE_URL = "/service/device";
+    public static final String FILTER_PAY_URL = "/service/order/scanPay";
+    public static final String FILTER_MANAGER_URL = "/service/manager";
+    public static final String FILTER_AGENT_URL = "/service/agent";
+    public static final String FILTER_APP_URL = "/service/app";
+
+    public static List<String> getFilterPattern(){
+        List<String> arr = new ArrayList<>();
+        arr.add(FILTER_USER_URL);
+        arr.add(FILTER_SCENE_URL);
+        arr.add(FILTER_DEVICE_URL);
+        arr.add(FILTER_PAY_URL);
+//        arr.add(FILTER_MANAGER_URL);
+//        arr.add(FILTER_AGENT_URL);
+        return arr;
+    }
+}

+ 78 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/controller/BaseController.java

@@ -0,0 +1,78 @@
+package com.fdkankan.web.controller;
+
+import com.fdkankan.common.util.DateEditor;
+import com.fdkankan.web.user.SSOLoginHelper;
+import com.fdkankan.web.user.SSOUser;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+import java.util.Objects;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.propertyeditors.StringTrimmerEditor;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+
+public class BaseController {
+    @Autowired
+    protected HttpServletRequest request;
+
+    @Autowired
+    protected HttpServletResponse response;
+
+    @Autowired
+    SSOLoginHelper ssoLoginHelper;
+
+    @InitBinder
+    protected void initBinder(WebDataBinder webDataBinder) {
+        webDataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
+        webDataBinder.registerCustomEditor(Date.class, new DateEditor(true));
+    }
+
+    protected String getToken(){
+        return request.getHeader("token");
+    }
+
+    protected Long getUserId(){
+        SSOUser ssoUser = ssoLoginHelper.loginCheck(request.getHeader("token"));
+        if(Objects.nonNull(ssoUser)){
+            return ssoUser.getId();
+        }
+        return null;
+    }
+
+    protected SSOUser getSsoUser(){
+        return ssoLoginHelper.loginCheck(request.getHeader("token"));
+    }
+
+    protected com.fdkankan.web.model.SSOUser getSsoUserV3(){
+        return ssoLoginHelper.loginCheckV3(request.getHeader("token"));
+    }
+
+    public static void output(HttpServletResponse resp, File file) {
+        OutputStream os = null;
+        BufferedInputStream bis = null;
+        byte[] buff = new byte[1024];
+        try {
+            os = resp.getOutputStream();
+            bis = new BufferedInputStream(new FileInputStream(file));
+            int i = 0;
+            while ((i = bis.read(buff)) != -1) {
+                os.write(buff, 0, i);
+                os.flush();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                bis.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

+ 50 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/controller/CustomErrorController.java

@@ -0,0 +1,50 @@
+package com.fdkankan.web.controller;
+
+import com.fdkankan.common.response.ResultData;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.boot.web.servlet.error.ErrorController;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * <p>
+ * 404 500 401等错误返回转发接口,统一返回格式
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/3/9
+ **/
+@Controller
+public class CustomErrorController implements ErrorController {
+
+    @RequestMapping("/error")
+    @ResponseBody
+    public ResultData handleError(HttpServletRequest request, HttpServletResponse response){
+
+        //获取statusCode:401,404,500
+        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
+        String message = "";
+        HttpStatus httpStatus = HttpStatus.valueOf(statusCode);
+        switch (httpStatus){
+            case INTERNAL_SERVER_ERROR :
+                message = "服务器内部异常!";
+                break;
+            case NOT_FOUND:
+                message = "接口不存在!";
+                break;
+            case FORBIDDEN:
+                message = "禁止访问!";
+                break;
+        }
+        return ResultData.error(statusCode, message);
+    }
+
+
+    @Override
+    public String getErrorPath() {
+        return "/error";
+    }
+}

+ 138 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/exception/GlobalExceptionHandler.java

@@ -0,0 +1,138 @@
+package com.fdkankan.web.exception;
+
+import cn.hutool.core.exceptions.ExceptionUtil;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.constant.ServerCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.response.ResultData;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.BindException;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.FieldError;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.multipart.MultipartException;
+
+/**
+ * 全局异常处理器
+ */
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+    /**
+     * 处理未知异常
+     */
+    @ResponseBody
+    @ExceptionHandler(value = Exception.class)
+    public ResultData exceptionHandler(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Exception e) throws Exception {
+            log.error("服务错误:", e);
+            //增加sentinel异常次数
+//            Tracer.trace(e);
+            return ResultData.error(ServerCode.SYSTEM_ERROR.code(), ExceptionUtil.stacktraceToString(e, 3000));
+    }
+
+    /**
+     * 限流熔断异常处理
+     * 如果在这里捕获的话,就需要在接口中加入@SentinelResour注解
+     */
+//    @ResponseBody
+//    @ExceptionHandler({FlowException.class, DegradeException.class})
+//    public ResultData flowExceptionHandler(HttpServletRequest httpServletRequest, Exception e) {
+//        String requestURI = httpServletRequest.getRequestURI();
+//        String resource = null;
+//        if(e instanceof FlowException){
+//            resource = ((FlowException) e).getRule().getResource();
+//        }
+//        if(e instanceof DegradeException){
+//            resource = ((DegradeException) e).getRule().getResource();
+//        }
+//
+//        log.error("请求限流:requestURI{},resource:{}", requestURI, resource);
+//        return ResultData.error(ServerCode.SYSTEM_ERROR.code(), "系统繁忙,请稍后重试");
+//    }
+
+    /**
+     * <p>
+            form表达提交,缺少参数异常处理
+     * </p>
+     * @author dengsixing
+     * @date 2022/4/14
+     * @param e
+     * @return com.fdkankan.common.response.ResultData
+     **/
+    @ResponseBody
+    @ExceptionHandler(value = MissingServletRequestParameterException.class)
+    public ResultData missingServletRequestParameterException(
+        MissingServletRequestParameterException e){
+        return ResultData.error(
+            ServerCode.PARAM_REQUIRED.code(),
+            ServerCode.PARAM_REQUIRED.formatMessage(e.getParameterName()));
+    }
+
+    /**
+     * <p>
+     form表达提交,文件为空异常处理
+     * </p>
+     * @author dengsixing
+     * @date 2022/4/14
+     * @param e
+     * @return com.fdkankan.common.response.ResultData
+     **/
+    @ResponseBody
+    @ExceptionHandler(value = MultipartException.class)
+    public ResultData multipartException(MultipartException e){
+        return ResultData.error(
+            ServerCode.PARAM_REQUIRED.code(),
+            ServerCode.PARAM_REQUIRED.formatMessage("文件"));
+    }
+
+
+    /**
+     * 参数校验异常拦截处理
+     */
+    @ResponseBody
+    @ExceptionHandler({BindException.class,MethodArgumentNotValidException.class})
+    public ResultData validationBodyException(Exception e) {
+        BindingResult result = null;
+        if(e instanceof MethodArgumentNotValidException){
+            result = ((MethodArgumentNotValidException) e).getBindingResult();
+        }
+        if(e instanceof BindException){
+            result = ((BindException) e).getBindingResult();
+        }
+        String message = "";
+        if (result.hasErrors()) {
+            List<ObjectError> errors = result.getAllErrors();
+            if (errors != null) {
+                errors.forEach(p -> {
+                    FieldError fieldError = (FieldError) p;
+                    log.error("参数校验错误:类:{},字段:{},错误信息:{}",fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
+                });
+                if (errors.size() > 0) {
+                    FieldError fieldError = (FieldError) errors.get(0);
+                    message = fieldError.getDefaultMessage();
+                }
+            }
+        }
+        return ResultData.error(ErrorCode.PARAM_REQUIRED.code(), message);
+    }
+
+
+    /**
+     * 处理业务异常
+     */
+    @ResponseBody
+    @ExceptionHandler(value = BusinessException.class)
+    public ResultData businessExceptionHandler(HttpServletRequest httpServletRequest, BusinessException e) {
+        log.info("业务异常code:{},message:{}", e.getCode(), e.getMessage());
+        return ResultData.error(e.getCode(), e.getMessage());
+    }
+}

+ 34 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/exception/JwtAuthenticationException.java

@@ -0,0 +1,34 @@
+package com.fdkankan.web.exception;
+
+import org.apache.shiro.ShiroException;
+
+public class JwtAuthenticationException extends ShiroException {
+
+    private static final long serialVersionUID = 2899335020273674736L;
+
+    private int code;
+
+    private String msg;
+
+    public JwtAuthenticationException(int code, String msg){
+        super(msg);
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+}

+ 10 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/factory/LogFactory.java

@@ -0,0 +1,10 @@
+package com.fdkankan.web.factory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LogFactory {
+    public static final Logger V_LOG = LoggerFactory.getLogger("visitLog");
+    public static final Logger P_LOG = LoggerFactory.getLogger("programLog");
+
+}

+ 113 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/jwt/JwtFilter.java

@@ -0,0 +1,113 @@
+package com.fdkankan.web.jwt;
+
+import com.alibaba.fastjson.JSON;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.response.ResultData;
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+public class JwtFilter extends BasicHttpAuthenticationFilter {
+    private static Logger log = LoggerFactory.getLogger("programLog");
+
+    private String loginType;
+
+    public JwtFilter(String loginType){
+        this.loginType = loginType;
+    }
+
+    /**
+     * 执行登录认证
+     *
+     * @param request
+     * @param response
+     * @param mappedValue
+     * @return
+     */
+    @Override
+    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+        try {
+            log.info("Step 1: 接口拦截shiro认证权限");
+            executeLogin(request, response);
+            String url = ((HttpServletRequest) request).getRequestURI();
+//            getSubject(request, response).checkPermission(url);
+            return true;
+        } catch (Exception e) {
+            // 认证出现异常,传递错误信息msg
+            String msg = e.getMessage();
+            // 获取应用异常(该Cause是导致抛出此throwable(异常)的throwable(异常))
+            Throwable throwable = e.getCause();
+            ResultData resultData = ResultData.error(3002, msg);
+            if (throwable instanceof BusinessException) {
+                resultData.setCode(((BusinessException) throwable).getCode());
+                resultData.setMessage(((BusinessException)throwable).getMessage());
+            }
+            // 直接返回Response信息
+            this.response(response, resultData);
+            return false;
+        }
+    }
+
+    /**
+     *
+     */
+    @Override
+    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
+        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+        String token = httpServletRequest.getHeader("token");
+
+        JwtToken jwtToken = new JwtToken(token, loginType);
+        // 提交给realm进行登入,如果错误他会抛出异常并被捕获
+        getSubject(request, response).login(jwtToken);
+        // 如果没有抛出异常则代表登入成功,返回true
+        return true;
+    }
+
+    /**
+     * 对跨域提供支持
+     */
+    @Override
+    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
+        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
+        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
+        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
+        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
+        // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
+        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
+            httpServletResponse.setStatus(HttpStatus.OK.value());
+            return false;
+        }
+        return super.preHandle(request, response);
+    }
+
+    /**
+     * 无需转发,直接返回Response信息
+     */
+    private void response(ServletResponse response, ResultData resultData) {
+        response.setCharacterEncoding("UTF-8");
+        response.setContentType("application/json; charset=utf-8");
+        PrintWriter out = null;
+        try {
+            out = response.getWriter();
+            out.append(JSON.toJSONString(resultData));
+            out.flush();
+            out.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (out != null){
+                out.close();
+            }
+        }
+    }
+
+}

+ 33 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/jwt/JwtToken.java

@@ -0,0 +1,33 @@
+package com.fdkankan.web.jwt;
+
+import org.apache.shiro.authc.AuthenticationToken;
+
+public class JwtToken implements AuthenticationToken {
+
+    private String token;
+
+    private String loginType;
+
+    public JwtToken(String token, String loginType){
+        this.token = token;
+        this.loginType = loginType;
+    }
+
+    @Override
+    public Object getPrincipal() {
+        return token;
+    }
+
+    @Override
+    public Object getCredentials() {
+        return token;
+    }
+
+    public String getLoginType() {
+        return loginType;
+    }
+
+    public void setLoginType(String loginType) {
+        this.loginType = loginType;
+    }
+}

+ 37 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/model/SSOUser.java

@@ -0,0 +1,37 @@
+package com.fdkankan.web.model;
+
+import java.io.Serializable;
+import java.util.Set;
+import lombok.Data;
+
+/**
+ * sso user
+ *
+ *  2018-04-02 19:59:49
+ */
+@Data
+public class SSOUser implements Serializable {
+
+    private static final long serialVersionUID = -2560069033053679931L;
+
+    private Long id;
+
+    private String userName;
+
+    private String password;
+
+    private String email;
+
+    private Set<String> permissionSet;
+
+    private Set<String> roleSet;
+
+    /**
+     * 是否相机登录,0-否,1-是
+     */
+    private Integer cameraLogin;
+
+    private Long cameraId;
+
+
+}

+ 60 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/realm/AgentJwtRealm.java

@@ -0,0 +1,60 @@
+package com.fdkankan.web.realm;
+
+import cn.hutool.core.util.StrUtil;
+import com.fdkankan.common.util.JwtUtil;
+import com.fdkankan.web.exception.JwtAuthenticationException;
+import com.fdkankan.web.jwt.JwtToken;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AgentJwtRealm extends AuthorizingRealm {
+    private static Logger log = LoggerFactory.getLogger("programLog");
+
+    @Override
+    public boolean supports(AuthenticationToken token) {
+        return token instanceof JwtToken;
+    }
+
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
+        return simpleAuthorizationInfo;
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
+        log.info("Step 2: Agent进行用户名正确与否验证");
+        String token = (String) auth.getCredentials();
+        if (StrUtil.isEmpty(token)){
+            throw new JwtAuthenticationException(3004, "无token,请重新登录");
+        }
+        // 获取 token 中的 userName
+        String userName = JwtUtil.getUsername(token);
+        if (StrUtil.isEmpty(userName)){
+            throw new JwtAuthenticationException(3004, "访问异常!");
+        }
+//        if (!userName.contains(SsoUtil.PREFIX_CACHE_AGENT)){
+//            throw new JwtAuthenticationException(3004, "用户未登录");
+//        }
+        if (!JwtUtil.isVerify(token, userName)) {
+            throw new JwtAuthenticationException(3004, "非法访问!");
+        }
+//        // 防止重复登陆, redisToken是最新登录获取的token
+//        String redisToken = JedisUtil.getStringValue(userName);
+//        if (StrUtil.isEmpty(redisToken) || !redisToken.equals(token)){
+//            throw new JwtAuthenticationException(3004, "用户未登录");
+//        }
+
+        return new SimpleAuthenticationInfo(token, token, "jwt_realm");
+    }
+}

+ 62 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/realm/AppJwtRealm.java

@@ -0,0 +1,62 @@
+package com.fdkankan.web.realm;
+
+import cn.hutool.core.util.StrUtil;
+import com.fdkankan.web.exception.JwtAuthenticationException;
+import com.fdkankan.web.jwt.JwtToken;
+import com.fdkankan.common.util.JwtUtil;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AppJwtRealm extends AuthorizingRealm {
+    private static Logger log = LoggerFactory.getLogger("programLog");
+
+    @Override
+    public boolean supports(AuthenticationToken token) {
+        return token instanceof JwtToken;
+    }
+
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
+        return simpleAuthorizationInfo;
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
+        log.info("Step 2: Agent进行用户名正确与否验证");
+        String token = (String) auth.getCredentials();
+        log.info("doGetAuthenticationInfo - step3 :" + token);
+        if (StrUtil.isEmpty(token)){
+            throw new JwtAuthenticationException(3004, "无token,请重新登录");
+        }
+        // 获取 token 中的 userName
+        String userName = JwtUtil.getUsername(token);
+        if (StrUtil.isEmpty(userName)){
+            throw new JwtAuthenticationException(3004, "访问异常!");
+        }
+        String regex = "^-?\\d+(\\.\\d+)?$";
+        if(userName.matches(regex)){
+            // TODO: 2021/12/21
+//            if (!JedisUtil.exists(SsoUtil.PREFIX_CACHE_CAMERA + userName)){
+//                throw new JwtAuthenticationException(3004, "用户未登录");
+//            }
+//            if (!JedisUtil.getStringValue(SsoUtil.PREFIX_CACHE_CAMERA + userName).contains(token)){
+//                throw new JwtAuthenticationException(3004, "用户未登录");
+//            }
+        }
+// TODO: 2021/12/21
+//        JedisUtil.expire(SsoUtil.PREFIX_CACHE_CAMERA + userName, 21600);
+
+        return new SimpleAuthenticationInfo(token, token, "jwt_realm");
+    }
+}

+ 61 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/realm/ManagerJwtRealm.java

@@ -0,0 +1,61 @@
+package com.fdkankan.web.realm;
+
+import cn.hutool.core.util.StrUtil;
+import com.fdkankan.web.exception.JwtAuthenticationException;
+import com.fdkankan.web.jwt.JwtToken;
+import com.fdkankan.common.util.JwtUtil;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ManagerJwtRealm extends AuthorizingRealm {
+    private static Logger log = LoggerFactory.getLogger("programLog");
+
+    @Override
+    public boolean supports(AuthenticationToken token) {
+        return token instanceof JwtToken;
+    }
+
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
+        return simpleAuthorizationInfo;
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
+        log.info("Step 2: Manager进行用户名正确与否验证");
+        String token = (String) auth.getCredentials();
+        if (StrUtil.isEmpty(token)){
+            throw new JwtAuthenticationException(3004, "无token,请重新登录");
+        }
+        // 获取 token 中的 userName
+        String userName = JwtUtil.getUsername(token);
+        if (StrUtil.isEmpty(userName)){
+            throw new JwtAuthenticationException(3004, "访问异常!");
+        }
+//        if (!userName.contains(SsoUtil.PREFIX_CACHE_MANAGER)){
+//            throw new JwtAuthenticationException(3004, "用户未登录");
+//        }
+        if (!JwtUtil.isVerify(token, userName)) {
+            throw new JwtAuthenticationException(3004, "非法访问!");
+        }
+        // 防止重复登陆, redisToken是最新登录获取的token
+        // TODO: 2021/12/21  
+//        String redisToken = JedisUtil.getStringValue(userName);
+//        if (StrUtil.isEmpty(redisToken) || !redisToken.equals(token)){
+//            throw new JwtAuthenticationException(3004, "用户未登录");
+//        }
+
+        return new SimpleAuthenticationInfo(token, token, "jwt_realm");
+    }
+}

+ 90 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/realm/UserJwtRealm.java

@@ -0,0 +1,90 @@
+package com.fdkankan.web.realm;
+
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.JwtUtil;
+import com.fdkankan.web.exception.JwtAuthenticationException;
+import com.fdkankan.web.jwt.JwtToken;
+import com.fdkankan.web.user.SSOLoginHelper;
+import com.fdkankan.web.user.SSOUser;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserJwtRealm extends AuthorizingRealm {
+    private static Logger log = LoggerFactory.getLogger("programLog");
+
+//    @Autowired
+//    private UserFeignClient userService;
+    @Autowired
+    private ObjectMapper mapper;
+
+    @Autowired
+    private SSOLoginHelper ssoLoginHelper;
+
+    /**
+     * 必须重写此方法,不然Shiro会报错
+     */
+    @Override
+    public boolean supports(AuthenticationToken token) {
+        return token instanceof JwtToken;
+    }
+    /**
+     * 只有当需要检测用户权限的时候才会调用此方法,例如checkRole,checkPermission之类的
+     */
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
+        String username = (String)principals.getPrimaryPrincipal();
+//        List list = principals.asList();
+//        Result result = userService.findByUserName(username);
+//        if (result.getCode() == Result.CODE_FAILURE){
+//            return authorizationInfo;
+//        }
+//        SSOUser dbUser = mapper.convertValue(result.getData(), SSOUser.class);
+//        authorizationInfo.setRoles(dbUser.getRoleSet());
+//        authorizationInfo.setStringPermissions(dbUser.getPermissionSet());
+        return authorizationInfo;
+    }
+    /**
+     * 默认使用此方法进行用户名正确与否验证,错误抛出异常即可。
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
+        log.info("Step 2: User进行用户名正确与否验证");
+        String token = (String) auth.getCredentials();
+        if (StrUtil.isEmpty(token)){
+            throw new JwtAuthenticationException(3004, "无token,请重新登录");
+        }
+        // 解密获得username,用于和数据库进行对比
+        String username = JwtUtil.getUsername(token);
+        if (username == null) {
+            throw new BusinessException(ErrorCode.TOKEN_ILLEGAL);
+        }
+        if (!JwtUtil.isVerify(token, username)) {
+            throw new BusinessException(ErrorCode.TOKEN_ILLEGAL);
+        }
+        // TODO: 2021/12/21
+        SSOUser ssoUser = this.ssoLoginHelper.loginCheck(token);
+        if (ssoUser == null){
+            throw new BusinessException(ErrorCode.TOKEN_NOT_FOUND);
+        }
+//
+//        // refresh
+        // TODO: 2021/12/21
+//        JedisUtil.expire(token, 21600);
+        return new SimpleAuthenticationInfo(username, token, "jwt_realm");
+    }
+}

+ 54 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/response/BaseResponseAdvice.java

@@ -0,0 +1,54 @@
+package com.fdkankan.web.response;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fdkankan.common.response.PageInfo;
+import com.fdkankan.common.response.ResultData;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+@RestControllerAdvice
+@Slf4j
+public class BaseResponseAdvice implements ResponseBodyAdvice<Object> {
+    @Override
+    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
+        return true;
+    }
+
+    @Override
+    public Object beforeBodyWrite(Object body, MethodParameter methodParameter,
+        MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass,
+        ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
+//        if(serverHttpRequest.getURI().getPath().contains("feign")){
+//            return body;
+//        }
+//        log.info("响应拦截成功。。。");
+//        List<String> strings = serverHttpRequest.getHeaders().get("Accept-Language");
+//        System.out.println(strings.get(0));
+
+        //admin监控请求,直接返回
+        if(serverHttpRequest.getURI().getPath().contains("actuator")){
+            return body;
+        }
+
+        if(body instanceof String){
+            return JSONObject.toJSONString(ResultData.ok(body));
+        }
+        if(body instanceof Page){
+            Page page = (Page) body;
+            return ResultData.ok(new PageInfo(page.getCurrent(), page.getSize(), page.getTotal(), page.getRecords()));
+        }
+        if (body instanceof ResultData) {
+            return body;
+        } else {
+            return ResultData.ok(body);
+        }
+    }
+}

+ 73 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/user/SSOLoginHelper.java

@@ -0,0 +1,73 @@
+package com.fdkankan.web.user;
+
+import com.fdkankan.common.constant.LoginType;
+import com.fdkankan.common.util.JwtUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SSOLoginHelper {
+
+    @Autowired
+    private SSOLoginStore ssoLoginStore;
+
+    public SSOUser loginCheck(String token) {
+        if (token != null && token.trim().length() > 0) {
+            String username = JwtUtil.getUsername(token);
+            SSOUser ssoUser = ssoLoginStore.get(username);
+            if (ssoUser != null) {
+                return ssoUser;
+            }
+        }
+        return null;
+    }
+
+    public com.fdkankan.web.model.SSOUser loginCheckV3(String token) {
+        if (token != null && token.trim().length() > 0) {
+            com.fdkankan.web.model.SSOUser ssoUser = ssoLoginStore.getV3(token);
+            if (ssoUser != null) {
+                return ssoUser;
+            }
+        }
+        return null;
+    }
+
+    public String login(String loginType,String userName) {
+        return this.login(loginType,userName,null, null);
+    }
+    public String login(String loginType,String userName,Integer time) {
+        return this.login(loginType,userName,time, null);
+    }
+    public String login(SSOUser ssoUser) {
+        String loginType = LoginType.USER.code();
+        String userName = ssoUser.getUserName();
+        return this.login(loginType,userName,null, ssoUser);
+    }
+    public String login(SSOUser ssoUser,Integer time) {
+        String loginType = LoginType.USER.code();
+        String userName = ssoUser.getUserName();
+        return this.login(loginType,userName,time, ssoUser);
+    }
+
+    /**
+     * @param loginType     登录类型
+     * @param userName      登录用户名
+     * @param time          过期时间,时间单位为秒,默认为 6小时 21600
+     * @param ssoUser       sooUser
+     */
+    public String login(String loginType,String userName,Integer time,
+        SSOUser ssoUser) {
+        String token = JwtUtil.createJWT(-1, userName,loginType);
+        ssoLoginStore.put(loginType,userName,token,time, ssoUser);
+        return token;
+    }
+
+    public  void logout(String token) {
+        String username = JwtUtil.getUsername(token);
+        String loginType = JwtUtil.getLoginType(token);
+        this.logout(loginType,username);
+    }
+    public  void logout(String loginType,String userName) {
+        ssoLoginStore.remove(loginType,userName);
+    }
+}

+ 97 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/user/SSOLoginStore.java

@@ -0,0 +1,97 @@
+package com.fdkankan.web.user;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.common.constant.LoginType;
+import com.fdkankan.redis.constant.RedisKey;
+import com.fdkankan.redis.util.RedisUtil;
+import java.util.Objects;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@Component
+public class SSOLoginStore {
+
+    @Resource
+    private RedisUtil redisUtil;
+    /**
+     * get
+     * @param userName
+     * @return
+     */
+    public SSOUser get(String userName) {
+        String redisKey = getSsoUserRedisKey(userName);
+        String objectValue =  redisUtil.get(redisKey);
+        if (objectValue != null) {
+            return JSONObject.parseObject(objectValue, SSOUser.class);
+        }
+        return null;
+    }
+
+
+    @Resource
+    @Qualifier("redisTemplate2")
+    private RedisTemplate redisTemplate2;
+
+    public com.fdkankan.web.model.SSOUser getV3(String token) {
+        String redisKey = "token#".concat(token);
+        Object obj = redisTemplate2.opsForValue().get(redisKey);
+        if(Objects.nonNull(obj)){
+            return (com.fdkankan.web.model.SSOUser)obj;
+        }
+        return null;
+    }
+
+    /**
+     * remove
+     * @param loginType     登录类型
+     * @param userName      登录用户名
+     */
+    public  void remove(String loginType,String userName) {
+        String redisKey = getTokenRedisKey(loginType,userName);
+        if(redisUtil.hasKey(redisKey)){
+            redisUtil.del(redisKey);
+        }
+        if(LoginType.USER.code().equals(loginType)  ){
+            String ssoUserRedisKey = getSsoUserRedisKey(userName);
+            if(redisUtil.hasKey(ssoUserRedisKey)){
+                redisUtil.del(ssoUserRedisKey);
+            }
+        }
+    }
+
+    /**
+     *  put
+     * @param loginType     登录类型
+     * @param userName      登录用户名
+     * @param token         token
+     * @param time          过期时间,时间单位为秒,默认为 6小时 21600
+     * @param ssoUser       sooUser
+     */
+    public  void put(String loginType, String userName, String token,Integer time, SSOUser ssoUser) {
+        if(time == null || time <=0 ){
+            time = RedisKey.USER_EXPIRE_TIME;
+        }
+        String redisKey = getTokenRedisKey(loginType,userName);
+        redisUtil.set(redisKey, token, time);
+        if(LoginType.USER.code().equals(loginType) && ssoUser!=null ){
+            redisUtil.set(getSsoUserRedisKey(userName),JSONObject.toJSONString(ssoUser),time);
+        }
+    }
+
+    /**
+     * 获取token key
+     */
+    private static String getTokenRedisKey(String loginType,String userName){
+        return String.format(RedisKey.TOKEN_USER, loginType,userName);
+    }
+    private static String getSsoUserRedisKey(String userName){
+        return String.format(RedisKey.SSO_USER,userName);
+    }
+
+
+}

+ 27 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/user/SSOUser.java

@@ -0,0 +1,27 @@
+package com.fdkankan.web.user;
+
+import lombok.Data;
+import lombok.ToString;
+
+import java.io.Serializable;
+import java.util.Set;
+
+@Data
+@ToString
+public class SSOUser implements Serializable {
+
+    private static final long serialVersionUID = -2560069033053679931L;
+
+    private Long id;
+
+    private String userName;
+
+    private String password;
+
+    private String email;
+
+    private Set<String> permissionSet;
+
+    private Set<String> roleSet;
+
+}

+ 21 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/util/SsoUtil.java

@@ -0,0 +1,21 @@
+package com.fdkankan.web.util;
+
+public class SsoUtil {
+
+    public static final String REDIRECT_URL = "redirect_url";
+    public static final String SSO_USER = "sso_user";
+    public static final String SSO_SERVER = "sso_server";
+    public static final String SSO_LOGIN = "/login";
+    public static final String SSO_LOGOUT = "/logout";
+    public static final String SSO_LOGOUT_PATH = "logoutPath";
+    public static final String PREFIX_SHIRO_CACHE = "shiro:cache:";
+    public static final String PREFIX_MSG_AUTH_CODE = "msg:auth:code:";
+    public static final String PREFIX_CACHE_MANAGER = "manager:";
+    public static final String PREFIX_CACHE_AGENT = "agent:";
+    public static final String PREFIX_CACHE_CAMERA = "camera:";
+    public static final String SSO_SESSIONID = "token";
+    public static final String PREFIX_CACHE_USERINFO = "user_info:";
+    public static final String PREFIX_MSG_NOT_CODE = "msg:not:code:";//短信重发验证
+
+    public static final String USER_TOKEN = "user:token:";
+}

+ 35 - 0
4dkankan-common-web/src/main/java/com/fdkankan/web/util/WebUtil.java

@@ -0,0 +1,35 @@
+package com.fdkankan.web.util;
+
+import cn.hutool.http.ContentType;
+import com.alibaba.fastjson.JSON;
+import java.util.HashMap;
+import javax.servlet.http.HttpServletRequest;
+import org.aspectj.lang.JoinPoint;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/6/9
+ **/
+public class WebUtil {
+
+    /**
+     * 获取请求参数中的场景码
+     * @param pjp
+     * @param request
+     * @return
+     */
+    public static String getNum(JoinPoint pjp, HttpServletRequest request){
+        Object[] args = pjp.getArgs();
+        String contentType = request.getContentType();
+        if(contentType.contains(ContentType.JSON.getValue())){
+            HashMap hashMap = JSON.parseObject(JSON.toJSONString(args[0]), HashMap.class);
+            return (String) hashMap.get("num");
+        }
+        return request.getParameter("num");
+    }
+
+}

+ 46 - 0
pom.xml

@@ -16,6 +16,7 @@
         <module>4dkankan-utils-email</module>
         <module>4dkankan-utils-rabbitmq</module>
         <module>4dkankan-utils-rubber-sheeting</module>
+        <module>4dkankan-common-web</module>
     </modules>
 
     <groupId>com.fdkankan</groupId>
@@ -43,6 +44,10 @@
         <java.version>1.8</java.version>
         <fastjson-version>1.2.83</fastjson-version>
         <hutool-version>5.7.17</hutool-version>
+        <spring.cloud-version>Hoxton.SR8</spring.cloud-version>
+        <servlet-api-version>2.4</servlet-api-version>
+        <shiro.version>1.7.1</shiro.version>
+        <spring.plugin.metadata-version>1.2.0.RELEASE</spring.plugin.metadata-version>
     </properties>
 
     <dependencies>
@@ -62,6 +67,29 @@
 
     <dependencyManagement>
         <dependencies>
+
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-all</artifactId>
+                <version>${hutool-version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.alibaba.cloud</groupId>
+                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
+                <version>2.2.7.RELEASE</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring.cloud-version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-dependencies</artifactId>
@@ -117,6 +145,24 @@
                 <version>2.5.0</version>
             </dependency>
 
+            <dependency>
+                <groupId>javax.servlet</groupId>
+                <artifactId>servlet-api</artifactId>
+                <version>${servlet-api-version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.shiro</groupId>
+                <artifactId>shiro-spring</artifactId>
+                <version>${shiro.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.plugin</groupId>
+                <artifactId>spring-plugin-metadata</artifactId>
+                <version>${spring.plugin.metadata-version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>