commit 19f671613a5e635d697c79d87f02283f5642e51a
Author: wangpengfei <1928057482@qq.com>
Date: Mon May 6 15:13:35 2024 +0800
初始化
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a70b169
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,116 @@
+# ---> Java
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+# ---> Maven
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+# https://github.com/takari/maven-wrapper#usage-without-binary-jar
+.mvn/wrapper/maven-wrapper.jar
+
+# ---> JetBrains
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+**/.idea/
+**/logs/
\ No newline at end of file
diff --git a/docs/HELP.md b/docs/HELP.md
new file mode 100644
index 0000000..e69de29
diff --git a/gateway/pom.xml b/gateway/pom.xml
new file mode 100644
index 0000000..0f6e47f
--- /dev/null
+++ b/gateway/pom.xml
@@ -0,0 +1,92 @@
+
+
+
+ share-store
+ com.yxt
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ com.yxt.gateway
+ gateway
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.0
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+ org.projectlombok
+ lombok
+ 1.18.24
+ true
+
+
+ org.springframework
+ spring-webmvc
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ io.lettuce
+ lettuce-core
+
+
+
+
+ redis.clients
+ jedis
+
+
+ com.alibaba
+ fastjson
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 2.5.6
+
+
+
+ repackage
+
+
+
+
+
+
+
+ src/main/resources
+
+ **/*.yml
+
+ false
+
+
+
+
\ No newline at end of file
diff --git a/gateway/src/main/java/com/yxt/wms/AuthFilter.java b/gateway/src/main/java/com/yxt/wms/AuthFilter.java
new file mode 100644
index 0000000..efe69bb
--- /dev/null
+++ b/gateway/src/main/java/com/yxt/wms/AuthFilter.java
@@ -0,0 +1,124 @@
+package com.yxt.wms;
+
+import com.alibaba.fastjson.JSON;
+import com.yxt.wms.utils.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.core.Ordered;
+import org.springframework.core.io.buffer.DataBufferFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import static com.yxt.wms.utils.HttpStatus.OVERDUE;
+
+/**
+ * @author dimengzhe
+ * @date 2020/12/2 9:52
+ * @description 网关鉴权
+ * 1.某些接口不需要不进行登录验证,如登录,注册,获取验证码等接口。(uri白名单)
+ * 2.某些接口需要登录验证,但是不需要刷新token有效时间,如客户端轮询请求的接口。
+ * 3.特定场景下IP黑、白名单。
+ * 4.处于安全考虑的接口流量控制。
+ */
+@Component
+public class AuthFilter implements GlobalFilter, Ordered {
+
+ private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
+ //过期时间设置为4小时
+ private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;
+ private final static long EXPIRE_TIME_APP = Constants.TOKEN_EXPIRE_APP * 60;
+
+ // 排除过滤的 uri 地址,nacos自行添加
+ @Autowired
+ private IgnoreWhiteProperties ignoreWhite;
+ @Autowired
+ private RedisUtil redisUtil;
+ /*
+ redis中数据存储结构为两个键值对
+ 键为用户ID,值为用户token,可以通过用户ID查询用户token,实现立刻失效用户token功能。
+ 键为用户token,值为用户数据,实现token有效性,用户数据缓存功能。
+ */
+
+ @Override
+ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+ String url = exchange.getRequest().getURI().getPath();
+ //1.uri白名单。 跳过不需要验证的路径
+ if (StringUtils.matches(url, ignoreWhite.getWhites())) {
+ return chain.filter(exchange);
+ } else if (StringUtils.matchesTwo(url, ignoreWhite.getWhitesTwo())) {
+ return chain.filter(exchange);
+ }
+ //2.验证有无令牌。 从请求的header中获取token
+ String token = getToken(exchange.getRequest());
+ if (StringUtils.isBlank(token)) {
+ return setUnauthorizedResponse(exchange, "令牌不能为空");
+ }
+ //3.验证token是否有效。(a.验证token是否合法 b.验证token是否过期)
+ //从redis缓存中获取key对应的内容
+ String userName = redisUtil.get(token);
+
+ if (StringUtils.isBlank(userName)) {
+
+ return setUnauthorizedResponse(exchange, "登录状态已过期");
+ }
+ //验签:需要验证token中的签名是否与用户sid一致,后台用密钥+userSid+token除签名以外的内容,重新生成签名,与token中的签名进行比较
+
+ //刷新token过期日期
+ if (token.contains("App")) {
+ redisUtil.expire(token, EXPIRE_TIME_APP);
+ } else {
+ redisUtil.expire(token, EXPIRE_TIME);
+ }
+
+ // 在请求中增加用户信息
+ ServerHttpRequest mutableReq = exchange.getRequest().mutate()
+ .header(CacheConstants.DETAILS_USERNAME, userName).build();
+ ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
+ return chain.filter(mutableExchange);
+ }
+
+ /**
+ * 鉴权异常处理
+ *
+ * @param exchange
+ * @param msg
+ * @return
+ */
+ private Mono setUnauthorizedResponse(ServerWebExchange exchange, String msg) {
+ ServerHttpResponse response = exchange.getResponse();
+ response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
+ response.setStatusCode(HttpStatus.OK);
+
+ log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
+
+ return response.writeWith(Mono.fromSupplier(() -> {
+ DataBufferFactory bufferFactory = response.bufferFactory();
+// return bufferFactory.wrap(JSON.toJSONBytes(com.yxt.anrui.utils.HttpStatus.OVERDUE));
+ return bufferFactory.wrap(JSON.toJSONBytes(ResultBean.fireFail().setCode(OVERDUE).setMsg(msg)));
+ }));
+ }
+
+ /**
+ * 获取请求token
+ */
+ private String getToken(ServerHttpRequest request) {
+ String token = request.getHeaders().getFirst(CacheConstants.HEADER);
+// if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX)) {
+// token = token.replace(CacheConstants.TOKEN_PREFIX, "");
+// }
+ return token;
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+}
diff --git a/gateway/src/main/java/com/yxt/wms/GatewayApplication.java b/gateway/src/main/java/com/yxt/wms/GatewayApplication.java
new file mode 100644
index 0000000..97cb509
--- /dev/null
+++ b/gateway/src/main/java/com/yxt/wms/GatewayApplication.java
@@ -0,0 +1,18 @@
+package com.yxt.wms;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+/**
+ * @author wangpengfei
+ * @date ${DATE} ${TIME}
+ */
+
+@EnableDiscoveryClient
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+public class GatewayApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(GatewayApplication.class, args);
+ }}
\ No newline at end of file
diff --git a/gateway/src/main/java/com/yxt/wms/RedisUtil.java b/gateway/src/main/java/com/yxt/wms/RedisUtil.java
new file mode 100644
index 0000000..5572564
--- /dev/null
+++ b/gateway/src/main/java/com/yxt/wms/RedisUtil.java
@@ -0,0 +1,300 @@
+package com.yxt.wms;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisStringCommands;
+import org.springframework.data.redis.core.*;
+import org.springframework.data.redis.core.types.Expiration;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.stereotype.Service;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author dimengzhe
+ * @date 2020/9/9 17:35
+ * @description redis工具类
+ */
+@Service
+public class RedisUtil {
+
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+
+ /**
+ * 字符串类型:根据key设置value值,如果key中的value存在,那么返回false
+ *
+ * @param key
+ * @param value
+ * @return
+ */
+ public Boolean setnx(final String key, final String value, final long expration, final TimeUnit timeUnit) {
+ return (Boolean) redisTemplate.execute(new RedisCallback() {
+ @Override
+ public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {
+ RedisSerializer redisSerializer = redisTemplate.getStringSerializer();
+ byte keys[] = redisSerializer.serialize(key);
+ byte values[] = redisSerializer.serialize(value);
+ return redisConnection.set(keys, values, Expiration.from(expration, timeUnit), RedisStringCommands.SetOption.SET_IF_ABSENT);
+ }
+ });
+ }
+
+ /**
+ * 写入缓存
+ *
+ * @param key
+ * @param value
+ * @return
+ */
+ public boolean set(final String key, final String value) {
+
+ boolean result = (boolean) redisTemplate.execute(new RedisCallback() {
+ @Override
+ public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
+ RedisSerializer serializer = redisTemplate.getStringSerializer();
+ connection.set(serializer.serialize(key), serializer.serialize(value));
+ return true;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * 写入缓存设置时效时间
+ *
+ * @param key
+ * @param value
+ * @return
+ */
+ public boolean set(final String key, Object value, Long expireTime) {
+ boolean result = false;
+ try {
+ ValueOperations operations = redisTemplate.opsForValue();
+ operations.set(key, value);
+ redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
+ result = true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+ /**
+ * 刷新缓存到期时间
+ * @param key
+ * @param expire
+ * @return
+ */
+ public boolean expire(String key, long expire) {
+ return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 读取缓存
+ *
+ * @param key
+ * @return
+ */
+ public String get(final String key) {
+ String result = (String) redisTemplate.execute(new RedisCallback() {
+ @Override
+ public String doInRedis(RedisConnection connection) throws DataAccessException {
+ RedisSerializer serializer = redisTemplate.getStringSerializer();
+ byte[] value = connection.get(serializer.serialize(key));
+ return serializer.deserialize(value);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * 正则获取key集合
+ *
+ * @param pattern
+ * @return
+ */
+ public Set keys(String pattern) {
+ Set keys = redisTemplate.keys(pattern);
+ return keys;
+ }
+
+
+ /**
+ * 批量删除对应的value
+ *
+ * @param keys
+ */
+ public void remove(final String... keys) {
+ for (String key : keys) {
+ remove(key);
+ }
+ }
+
+ /**
+ * 批量删除key
+ *
+ * @param pattern
+ */
+ public void removePattern(final String pattern) {
+ Set keys = redisTemplate.keys(pattern);
+ if (keys.size() > 0) {
+ redisTemplate.delete(keys);
+ }
+
+ }
+
+
+ public Long remove(final String key) {
+ return (Long) redisTemplate.execute(new RedisCallback() {
+ @Override
+ public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
+ RedisSerializer serializer = redisTemplate.getStringSerializer();
+ byte keys[] = serializer.serialize(key);
+ return redisConnection.del(keys);
+ }
+ });
+ }
+
+
+ /**
+ * 判断缓存中是否有对应的value
+ *
+ * @param key
+ * @return
+ */
+ public boolean exists(final String key) {
+ return redisTemplate.hasKey(key);
+ }
+
+
+ /**
+ * 哈希 添加
+ *
+ * @param key
+ * @param hashKey
+ * @param value
+ */
+ public void hmSet(String key, Object hashKey, Object value) {
+ HashOperations hash = redisTemplate.opsForHash();
+ hash.put(key, hashKey, value);
+ }
+
+ /**
+ * 哈希获取数据
+ *
+ * @param key
+ * @param hashKey
+ * @return
+ */
+ public String hmGet(String key, Object hashKey) {
+ HashOperations hash = redisTemplate.opsForHash();
+ return hash.get(key, hashKey);
+ }
+
+ /**
+ * 获取哈希 keys
+ *
+ * @param key
+ * @return
+ */
+ public Set hmGetKeys(String key) {
+ HashOperations hash = redisTemplate.opsForHash();
+ return hash.keys(key);
+ }
+
+ /**
+ * 删除集合中的key
+ *
+ * @param key
+ * @param hashKey
+ */
+ public void hmDelete(String key, Object hashKey) {
+ HashOperations hash = redisTemplate.opsForHash();
+ hash.delete(key, hashKey);
+ }
+
+ /**
+ * 列表添加
+ *
+ * @param k
+ * @param v
+ */
+ public void lPush(String k, Object v) {
+ ListOperations list = redisTemplate.opsForList();
+ list.rightPush(k, v);
+ }
+
+ /**
+ * 列表获取
+ *
+ * @param k
+ * @param l
+ * @param l1
+ * @return
+ */
+ public List