diff --git a/config/application.yml b/config/application.yml index f8ebfd8..f465ade 100644 --- a/config/application.yml +++ b/config/application.yml @@ -3,6 +3,7 @@ spring: host: 192.168.1.53 port: 6379 timeout: 60000 + password: vmvnv1v2VV. application: name: gateway-server-v12 profiles: @@ -73,6 +74,10 @@ management: gateway: enabled: false endpoint: + gateway: + enabled: false + env: + enabled: false health: enabled: true # 启用健康检查端点 info: diff --git a/pom.xml b/pom.xml index b9c2b23..9bb35ec 100644 --- a/pom.xml +++ b/pom.xml @@ -11,13 +11,13 @@ </parent> <groupId>com.example</groupId> <artifactId>gateway</artifactId> - <version>1.0-WIN</version> + <version>1.0-linux</version> <name>gateway</name> <description>gateway project for Spring Boot</description> <properties> <java.version>1.8</java.version> - <spring-cloud.version>Greenwich.SR2</spring-cloud.version> + <spring-cloud.version>Greenwich.SR6</spring-cloud.version> </properties> <dependencies> diff --git a/src/main/java/com/example/gateway/filter/WrapperResponseGlobalFilter.java b/src/main/java/com/example/gateway/filter/WrapperResponseGlobalFilter.java index 53944fa..d471b42 100644 --- a/src/main/java/com/example/gateway/filter/WrapperResponseGlobalFilter.java +++ b/src/main/java/com/example/gateway/filter/WrapperResponseGlobalFilter.java @@ -58,7 +58,7 @@ public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered { if(request.getPath().toString().contains(LOGIN)){ return chain.filter(exchange); } - boolean flag = UrlFilter(request); + boolean flag = urlFilter(request); if(!flag){ exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); @@ -119,36 +119,50 @@ public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered { return -2; } - public boolean UrlFilter(ServerHttpRequest request) { - //先鉴权匿名者可访问的接口 - if (anonymousUrlFilter(request)){ + public boolean urlFilter(ServerHttpRequest request) { + // 鉴权匿名者可访问的接口 + if (anonymousUrlFilter(request)) { return true; } - String token = ""; - if (!request.getPath().toString().contains(LOGIN)) { - HttpHeaders rqHeader = request.getHeaders(); - if(rqHeader.containsKey("Authorization")){ - token = rqHeader.get("Authorization").toString(); - token = token.substring(1, token.length() - 1); - log.info("[TOKEN]-Request Authorization INFO is:[{}]",token); - } - } - String redisKey = token.replace("Bearer ", ""); - log.info("[REDIS-KEY]-is:[{}]",redisKey); - String json = stringRedisTemplate.opsForValue().get(redisKey); - if (json != null) { - List<PERMISSION> permissionList = JsonToBean.jsonToUser(json); - for (PERMISSION permission : permissionList) { - log.trace("访问url:[{}]<->权限[{}]",request.getPath().toString(),permission.getUrl()); - if (pathMatcher.match(permission.getUrl(), request.getPath().toString())) { - log.info("[FILTER]-[URL:{}]->鉴权成功",request.getPath().toString()); - return true; + + // 获取请求路径 + String path = request.getPath().toString(); + + // 如果不是登录请求,尝试获取并处理Authorization头 + if (!path.contains(LOGIN)) { + HttpHeaders headers = request.getHeaders(); + String token = headers.getFirst("Authorization"); + + // 如果存在Authorization头,并且是Bearer类型 + if (token != null && token.startsWith("Bearer ")) { + token = token.substring(7); // "Bearer ".length() + log.info("[TOKEN]-Request Authorization INFO is:[{}]", token); + + // 构建Redis键 + String redisKey = token; + log.info("[REDIS-KEY]-is:[{}]", redisKey); + + // 尝试从Redis中获取用户信息 + String json = stringRedisTemplate.opsForValue().get(redisKey); + if (json != null) { + List<PERMISSION> permissionList = JsonToBean.jsonToUser(json); + + // 使用并行流优化循环 + if (permissionList.parallelStream().anyMatch(permission -> { + log.trace("访问url:[{}]<->权限[{}]", path, permission.getUrl()); + return pathMatcher.match(permission.getUrl(), path); + })) { + log.info("[FILTER]-[URL:{}]->鉴权成功", path); + return true; + } + } else { + log.warn("[FILTER]-没有对应token的redis缓存,鉴权失败"); } } - }else { - log.info("[FILTER]-没有对应token的redis缓存,鉴权失败"); } - log.info("[FILTER]-[URL:{}]->鉴权失败",request.getPath().toString()); + + // 如果未通过任何鉴权检查,记录失败并返回false + log.warn("[FILTER]-[URL:{}]->鉴权失败", path); return false; } @@ -159,6 +173,7 @@ public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered { */ public boolean anonymousUrlFilter(ServerHttpRequest request){ //内部服务接口,不允许外部访问 + System.out.println("request.getPath().toString() = " + request.getPath().toString()); if(pathMatcher.match("/**/anonymous/**", request.getPath().toString())) { return true; } diff --git a/src/main/resources/logback-dev.xml b/src/main/resources/logback-dev.xml new file mode 100644 index 0000000..de50ea0 --- /dev/null +++ b/src/main/resources/logback-dev.xml @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--参考文档链接:https://blog.csdn.net/qq_34912478/article/details/80877132--> +<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 --> +<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true --> +<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 --> +<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 --> +<configuration scan="true" scanPeriod="10 seconds"> + + <!--<include resource="org/springframework/boot/logging/logback/base.xml" />--> + + <contextName>logback</contextName> + <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 --> + <property name="log.path" value="./logs" /> + + <!-- 彩色日志 --> + <!-- 彩色日志依赖的渲染类 --> + <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /> + <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /> + <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" /> + <!-- 彩色日志格式 --> + <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/> + + + <!--输出到控制台--> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息--> + <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> + <level>INFO</level> + </filter> + <encoder> + <Pattern>${CONSOLE_LOG_PATTERN}</Pattern> + <!-- 设置字符集 --> + <charset>UTF-8</charset> + </encoder> + </appender> + + + <!--输出到文件--> + + <!-- 时间滚动输出 level为 DEBUG 日志 --> + <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <!-- 正在记录的日志文件的路径及文件名 --> + <file>${log.path}/log_debug.log</file> + <!--日志文件输出格式--> + <encoder> + <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> + <charset>UTF-8</charset> <!-- 设置字符集 --> + </encoder> + <!-- 日志记录器的滚动策略,按日期,按大小记录 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志归档 --> + <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>100MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + <!--日志文件保留天数--> + <maxHistory>15</maxHistory> + </rollingPolicy> + <!-- 此日志文件只记录debug级别的 --> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>debug</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- 时间滚动输出 level为 INFO 日志 --> + <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <!-- 正在记录的日志文件的路径及文件名 --> + <file>${log.path}/log_info.log</file> + <!--日志文件输出格式--> + <encoder> + <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> + <charset>UTF-8</charset> + </encoder> + <!-- 日志记录器的滚动策略,按日期,按大小记录 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 每天日志归档路径以及格式 --> + <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>100MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + <!--日志文件保留天数--> + <maxHistory>15</maxHistory> + </rollingPolicy> + <!-- 此日志文件只记录info级别的 --> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>info</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- 时间滚动输出 level为 WARN 日志 --> + <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <!-- 正在记录的日志文件的路径及文件名 --> + <file>${log.path}/log_warn.log</file> + <!--日志文件输出格式--> + <encoder> + <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> + <charset>UTF-8</charset> <!-- 此处设置字符集 --> + </encoder> + <!-- 日志记录器的滚动策略,按日期,按大小记录 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>100MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + <!--日志文件保留天数--> + <maxHistory>15</maxHistory> + </rollingPolicy> + <!-- 此日志文件只记录warn级别的 --> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>warn</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + + <!-- 时间滚动输出 level为 ERROR 日志 --> + <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <!-- 正在记录的日志文件的路径及文件名 --> + <file>${log.path}/log_error.log</file> + <!--日志文件输出格式--> + <encoder> + <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> + <charset>UTF-8</charset> <!-- 此处设置字符集 --> + </encoder> + <!-- 日志记录器的滚动策略,按日期,按大小记录 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>100MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + <!--日志文件保留天数--> + <maxHistory>15</maxHistory> + </rollingPolicy> + <!-- 此日志文件只记录ERROR级别的 --> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- + <logger>用来设置某一个包或者具体的某一个类的日志打印级别、 + 以及指定<appender>。<logger>仅有一个name属性, + 一个可选的level和一个可选的addtivity属性。 + name:用来指定受此logger约束的某一个包或者具体的某一个类。 + level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, + 还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。 + 如果未设置此属性,那么当前logger将会继承上级的级别。 + addtivity:是否向上级logger传递打印信息。默认是true。 + --> + <!--<logger name="org.springframework.web" level="info"/>--> + <!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>--> + <!-- + 使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作: + 第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息 + 第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别: + --> + + + <!-- + root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性 + level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, + 不能设置为INHERITED或者同义词NULL。默认是DEBUG + 可以包含零个或多个元素,标识这个appender将会添加到这个logger。 + --> + + <!--开发环境:打印控制台--> + <springProfile name="dev"> + <root level="INFO"> + <appender-ref ref="CONSOLE" /> + <appender-ref ref="DEBUG_FILE" /> + <appender-ref ref="INFO_FILE" /> + <appender-ref ref="WARN_FILE" /> + <appender-ref ref="ERROR_FILE" /> + </root> + </springProfile> + + <!--生产环境:输出到文件--> + <springProfile name="pro"> + <root level="info"> + <appender-ref ref="CONSOLE" /> + <appender-ref ref="DEBUG_FILE" /> + <appender-ref ref="INFO_FILE" /> + <appender-ref ref="ERROR_FILE" /> + <appender-ref ref="WARN_FILE" /> + </root> + </springProfile> + +</configuration> \ No newline at end of file