diff --git a/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/annotation/Auth.java b/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/annotation/Auth.java
new file mode 100644
index 0000000..f7dbd36
--- /dev/null
+++ b/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/annotation/Auth.java
@@ -0,0 +1,18 @@
+package com.qiuguo.iot.base.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 强制登陆
+ *
+ * @author weiyachao
+ * @since 2023/9/20 15:55
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Auth {
+
+}
diff --git a/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/constans/RedisConstans.java b/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/constans/RedisConstans.java
index 8110227..0214625 100644
--- a/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/constans/RedisConstans.java
+++ b/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/constans/RedisConstans.java
@@ -6,4 +6,6 @@ package com.qiuguo.iot.base.constans;
public class RedisConstans {
public static String DEVICE_INFO = "device::info::";
+
+ public static String IOT_TOKEN = "iot_token:";
}
diff --git a/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/constans/UserAuthContains.java b/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/constans/UserAuthContains.java
new file mode 100644
index 0000000..b916128
--- /dev/null
+++ b/iot-common/iot-base/src/main/java/com/qiuguo/iot/base/constans/UserAuthContains.java
@@ -0,0 +1,16 @@
+package com.qiuguo.iot.base.constans;
+
+/**
+ * XXX
+ *
+ * @author weiyachao 包含
+ * @since 2023/9/20 16:25
+ */
+public interface UserAuthContains {
+
+ String API_TOKEN = "Api-Token";
+
+ String API_TYPE = "Api-Type";
+
+
+}
diff --git a/iot-modules/iot-box-user-api/pom.xml b/iot-modules/iot-box-user-api/pom.xml
index 041cf45..b240751 100644
--- a/iot-modules/iot-box-user-api/pom.xml
+++ b/iot-modules/iot-box-user-api/pom.xml
@@ -62,6 +62,11 @@
${hsweb.orm.version}
+
+ org.springframework.boot
+ spring-boot-starter-data-redis-reactive
+
+
org.hswebframework.web
hsweb-starter
diff --git a/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/IotBoxUserApiApplication.java b/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/IotBoxUserApiApplication.java
index 13cd50b..17269cf 100644
--- a/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/IotBoxUserApiApplication.java
+++ b/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/IotBoxUserApiApplication.java
@@ -4,10 +4,12 @@ import com.tuya.connector.spring.annotations.ConnectorScan;
import org.hswebframework.web.crud.annotation.EnableEasyormRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication(scanBasePackages = {"com.qiuguo.iot.user.api", "com.qiuguo.iot.data.service"})
@EnableEasyormRepository(value = "com.qiuguo.iot.data.entity.*")
@ConnectorScan(basePackages = "com.qiuguo.iot.user.api.service")
+@EnableAspectJAutoProxy
public class IotBoxUserApiApplication {
public static void main(String[] args) {
diff --git a/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/config/AuthAspect.java b/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/config/AuthAspect.java
new file mode 100644
index 0000000..5a6dc21
--- /dev/null
+++ b/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/config/AuthAspect.java
@@ -0,0 +1,50 @@
+package com.qiuguo.iot.user.api.config;
+
+import com.qiuguo.iot.base.annotation.Auth;
+import com.qiuguo.iot.base.constans.UserAuthContains;
+import java.lang.reflect.Method;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+
+/**
+ * XXX
+ *
+ * @author weiyachao
+ * @since 2023/9/20 18:50
+ */
+
+@Aspect
+@Component
+public class AuthAspect {
+
+ @Autowired
+ private ReactiveStringRedisTemplate reactiveRedisTemplate;
+ // @Autowired(required = false)
+ // private ServerWebExchange serverWebExchange;
+ //
+ // @Autowired
+ // private ServerHttpRequest httpServletRequest;
+
+
+
+ @Around("@annotation(com.qiuguo.iot.base.annotation.Auth)") // 切入点表达式,这里使用了自定义注解
+ public Object authenticate(ProceedingJoinPoint joinPoint) throws Throwable {
+
+
+ // String first = httpServletRequest.getHeaders().getFirst(UserAuthContains.API_TOKEN);
+ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+ Method method = signature.getMethod();
+ Auth annotation = method.getAnnotation(Auth.class);
+ System.out.println("annotation = " + annotation);
+
+ return joinPoint.proceed();
+ }
+
+
+}
diff --git a/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/filter/AuthFilter.java b/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/filter/AuthFilter.java
new file mode 100644
index 0000000..50014c2
--- /dev/null
+++ b/iot-modules/iot-box-user-api/src/main/java/com/qiuguo/iot/user/api/filter/AuthFilter.java
@@ -0,0 +1,70 @@
+package com.qiuguo.iot.user.api.filter;
+
+import com.qiuguo.iot.base.annotation.Auth;
+import com.qiuguo.iot.base.constans.RedisConstans;
+import com.qiuguo.iot.base.constans.UserAuthContains;
+import java.lang.annotation.ElementType;
+import java.time.Duration;
+import java.util.Map;
+import javax.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.data.redis.core.ReactiveRedisTemplate;
+import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
+import org.springframework.util.ObjectUtils;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import org.springframework.web.servlet.HandlerMapping;
+import reactor.core.publisher.Mono;
+
+/**
+ * XXX
+ *
+ * @author weiyachao
+ * @since 2023/9/20 16:06
+ */
+@Configuration
+@Slf4j
+@Order(-1)
+public class AuthFilter implements WebFilter {
+
+ // @Autowired
+ private ReactiveStringRedisTemplate reactiveRedisTemplate;
+
+ @Override
+ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
+ HandlerMethod handlerMethod = exchange.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
+ Object attribute = exchange.getAttribute("org.springframework.web.server.ServerWebExchange.LOG_ID");
+ System.out.println("attribute = " + attribute);
+ if (handlerMethod != null && handlerMethod.getMethod().isAnnotationPresent(Auth.class)) {
+ // 如果请求方法上有 Auth 注解,执行登录验证逻辑
+ String api_token = exchange.getRequest().getHeaders().getFirst(UserAuthContains.API_TOKEN);
+ String api_type = exchange.getRequest().getHeaders().getFirst(UserAuthContains.API_TYPE);
+ if (ObjectUtils.isEmpty(api_token) || ObjectUtils.isEmpty(api_type)) {
+ return Mono.error(new RuntimeException("未登录"));
+ }
+ String key = RedisConstans.IOT_TOKEN.concat(api_token);
+ return reactiveRedisTemplate.getExpire(key).map(Duration::getSeconds).flatMap(ttl -> {
+ if (ttl == -1) {
+ // 用户没登陆
+ return Mono.error(new RuntimeException("未登录"));
+ } else if (ttl <= 3600) {
+ // token 将要失效
+ return reactiveRedisTemplate.expire(key, Duration.ofDays(7))
+ .then(chain.filter(exchange));
+ } else {
+ // 正常登录
+ return chain.filter(exchange);
+ }
+ });
+ }
+
+ return chain.filter(exchange);
+ }
+
+}