207
m2pool-gateway/m2pool-gateway.iml
Normal file
207
m2pool-gateway/m2pool-gateway.iml
Normal file
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="Spring" name="Spring">
|
||||
<configuration />
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-gateway:3.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter:3.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-rsa:1.0.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.bouncycastle:bcpkix-jdk15on:1.68" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.bouncycastle:bcprov-jdk15on:1.68" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-gateway-server:3.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-webflux:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-reactor-netty:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.projectreactor.netty:reactor-netty-http:1.0.18" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec-http:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec-http2:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver-dns:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec-dns:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver-dns-native-macos:osx-x86_64:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver-dns-classes-macos:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-epoll:linux-x86_64:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-unix-common:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-transport-classes-epoll:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.projectreactor.netty:reactor-netty-core:1.0.18" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-handler-proxy:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec-socks:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-webflux:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2021.0.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-alibaba-commons:2021.0.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.nacos:nacos-client:2.0.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.13.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpasyncclient:4.1.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.15" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore-nio:4.4.15" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.13" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.reflections:reflections:0.9.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.guava:guava:20.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.javassist:javassist:3.21.0-GA" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.prometheus:simpleclient:0.12.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.prometheus:simpleclient_tracer_otel:0.12.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.prometheus:simpleclient_tracer_common:0.12.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.prometheus:simpleclient_tracer_otel_agent:0.12.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.29" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.spring:spring-context-support:1.0.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-commons:3.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.6.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-context:3.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config:2021.0.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel:2021.0.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-transport-simple-http:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-transport-common:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-annotation-aspectj:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-core:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-circuitbreaker-sentinel:2021.0.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-reactor-adapter:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-spring-webflux-adapter:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-spring-webmvc-adapter:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-parameter-flow-control:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-cluster-server-default:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-cluster-common-default:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.76.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-cluster-client-default:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-alibaba-sentinel-datasource:2021.0.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-alibaba-sentinel-gateway:2021.0.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-api-gateway-adapter-common:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-spring-cloud-gateway-adapter:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-datasource-nacos:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-datasource-extension:1.8.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-actuator:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.17.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.17.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-actuator-autoconfigure:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-actuator:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.micrometer:micrometer-core:1.8.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hdrhistogram:HdrHistogram:2.1.12" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.latencyutils:LatencyUtils:2.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-loadbalancer:3.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.17" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.projectreactor.addons:reactor-extra:3.4.8" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.penggle:kaptcha:2.3.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.jhlabs:filters:2.0.235-1" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-webmvc:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-core:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.11.22" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger.core.v3:swagger-annotations:2.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.github.classgraph:classgraph:4.8.83" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-webflux:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.36" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:2.0.0.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.6.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.6.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.13.2" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.mapstruct:mapstruct:1.3.1.Final" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.projectlombok:lombok-maven-plugin:1.18.6.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.projectlombok:lombok:1.18.24" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.sonatype.plexus:plexus-build-api:0.0.7" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.codehaus.plexus:plexus-utils:1.5.8" level="project" />
|
||||
<orderEntry type="module" module-name="common-redis" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.6.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.6.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.6.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.1.8.RELEASE" level="project" />
|
||||
<orderEntry type="module" module-name="api-system" />
|
||||
<orderEntry type="module" module-name="common-core" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-openfeign:3.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-openfeign-core:3.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.github.openfeign.form:feign-form-spring:3.8.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.github.openfeign.form:feign-form:3.8.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.github.openfeign:feign-core:11.8" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.github.openfeign:feign-slf4j:11.8" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-loadbalancer:3.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-cache:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.stoyanr:evictor:1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba:transmittable-thread-local:2.12.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:4.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.3.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.2.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.0.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.4.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:4.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-validation:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.62" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.2.3.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.13.2.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.80" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-io:commons-io:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-fileupload:commons-fileupload:1.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:4.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.poi:poi:4.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-math3:3.6.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.zaxxer:SparseBitSet:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml-schemas:4.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlbeans:xmlbeans:3.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-mail:2.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.sun.mail:jakarta.mail:1.6.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-bootstrap:3.1.1" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
128
m2pool-gateway/pom.xml
Normal file
128
m2pool-gateway/pom.xml
Normal file
@@ -0,0 +1,128 @@
|
||||
<?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>m2pool</artifactId>
|
||||
<groupId>com.m2pool</groupId>
|
||||
<version>3.5.0</version>
|
||||
</parent>
|
||||
<description>gateway网关模块</description>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>m2pool-gateway</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- SpringCloud Gateway -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Sentinel Gateway -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Sentinel Datasource Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot Actuator -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Loadbalancer -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--验证码 -->
|
||||
<dependency>
|
||||
<groupId>com.github.penggle</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Swagger -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.fox.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>${swagger.fox.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-maven-plugin</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- m2pool Common Redis-->
|
||||
<dependency>
|
||||
<groupId>com.m2pool</groupId>
|
||||
<artifactId>common-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.m2pool</groupId>
|
||||
<artifactId>api-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.m2pool</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.m2pool.gateway;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
|
||||
/**
|
||||
* @Description 网关启动程序
|
||||
* @Date 2024/6/13 12:05
|
||||
* @Author dy
|
||||
*/
|
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
|
||||
public class M2PoolGatewayApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(M2PoolGatewayApplication.class,args);
|
||||
System.out.println("网关启动成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.m2pool.gateway.config;
|
||||
|
||||
import com.google.code.kaptcha.impl.DefaultKaptcha;
|
||||
import com.google.code.kaptcha.util.Config;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static com.google.code.kaptcha.Constants.*;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @Description 验证码配置
|
||||
* @Date 2024/6/13 10:55
|
||||
* @Author dy
|
||||
*/
|
||||
@Configuration
|
||||
public class CaptchaConfig {
|
||||
|
||||
@Bean(name = "captchaProducer")
|
||||
public DefaultKaptcha getKaptchaBean()
|
||||
{
|
||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
||||
Properties properties = new Properties();
|
||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||
properties.setProperty(KAPTCHA_BORDER, "yes");
|
||||
// 验证码文本字符颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
|
||||
// 验证码图片宽度 默认为200
|
||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
||||
// 验证码图片高度 默认为50
|
||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
||||
// 验证码文本字符大小 默认为40
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
|
||||
// KAPTCHA_SESSION_KEY
|
||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
|
||||
// 验证码文本字符长度 默认为5
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
|
||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
||||
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
||||
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
||||
Config config = new Config(properties);
|
||||
defaultKaptcha.setConfig(config);
|
||||
return defaultKaptcha;
|
||||
}
|
||||
|
||||
@Bean(name = "captchaProducerMath")
|
||||
public DefaultKaptcha getKaptchaBeanMath()
|
||||
{
|
||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
||||
Properties properties = new Properties();
|
||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||
properties.setProperty(KAPTCHA_BORDER, "yes");
|
||||
// 边框颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
|
||||
// 验证码文本字符颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
|
||||
// 验证码图片宽度 默认为200
|
||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
||||
// 验证码图片高度 默认为50
|
||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
||||
// 验证码文本字符大小 默认为40
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
|
||||
// KAPTCHA_SESSION_KEY
|
||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
|
||||
// 验证码文本生成器
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.m2pool.gateway.config.KaptchaTextCreator");
|
||||
// 验证码文本字符间距 默认为2
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
|
||||
// 验证码文本字符长度 默认为5
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
|
||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
||||
// 验证码噪点颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
|
||||
// 干扰实现类
|
||||
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
|
||||
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
||||
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
||||
Config config = new Config(properties);
|
||||
defaultKaptcha.setConfig(config);
|
||||
return defaultKaptcha;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.m2pool.gateway.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.cors.reactive.CorsUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2024/6/13 10:49
|
||||
* @Author dy
|
||||
*/
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
/**
|
||||
* 这里为支持的请求头,如果有自定义的header字段请自己添加
|
||||
*/
|
||||
private static final String ALLOWED_HEADERS = "X-Requested-With, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, Admin-Token, App-Token,os,from,model,net,API-KEY";
|
||||
private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";
|
||||
private static final String ALLOWED_ORIGIN = "*";
|
||||
private static final String ALLOWED_EXPOSE = "*";
|
||||
private static final String MAX_AGE = "18000L";
|
||||
|
||||
@Bean
|
||||
public WebFilter corsFilter()
|
||||
{
|
||||
return (ServerWebExchange ctx, WebFilterChain chain) -> {
|
||||
ServerHttpRequest request = ctx.getRequest();
|
||||
if (CorsUtils.isCorsRequest(request))
|
||||
{
|
||||
ServerHttpResponse response = ctx.getResponse();
|
||||
HttpHeaders headers = response.getHeaders();
|
||||
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
|
||||
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
|
||||
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
|
||||
headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
|
||||
headers.add("Access-Control-Max-Age", MAX_AGE);
|
||||
headers.add("Access-Control-Allow-Credentials", "true");
|
||||
if (request.getMethod() == HttpMethod.OPTIONS)
|
||||
{
|
||||
response.setStatusCode(HttpStatus.OK);
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
return chain.filter(ctx);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.m2pool.gateway.config;
|
||||
|
||||
import com.m2pool.gateway.handler.SentinelFallbackHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* @Description 网关限流配置
|
||||
* @Date 2024/6/13 10:07
|
||||
* @Author dy
|
||||
*/
|
||||
@Configuration
|
||||
public class GatewayConfig {
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public SentinelFallbackHandler sentinelGatewayExceptionHandler()
|
||||
{
|
||||
return new SentinelFallbackHandler();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.m2pool.gateway.config;
|
||||
|
||||
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @Description 验证码文本生成器
|
||||
* @Date 2024/6/13 10:10
|
||||
* @Author dy
|
||||
*/
|
||||
public class KaptchaTextCreator extends DefaultTextCreator {
|
||||
|
||||
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
|
||||
|
||||
@Override
|
||||
public String getText()
|
||||
{
|
||||
Integer result = 0;
|
||||
Random random = new Random();
|
||||
int x = random.nextInt(10);
|
||||
int y = random.nextInt(10);
|
||||
StringBuilder suChinese = new StringBuilder();
|
||||
int randomoperands = (int) Math.round(Math.random() * 2);
|
||||
if (randomoperands == 0)
|
||||
{
|
||||
result = x * y;
|
||||
suChinese.append(CNUMBERS[x]);
|
||||
suChinese.append("*");
|
||||
suChinese.append(CNUMBERS[y]);
|
||||
}
|
||||
else if (randomoperands == 1)
|
||||
{
|
||||
if (!(x == 0) && y % x == 0)
|
||||
{
|
||||
result = y / x;
|
||||
suChinese.append(CNUMBERS[y]);
|
||||
suChinese.append("/");
|
||||
suChinese.append(CNUMBERS[x]);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = x + y;
|
||||
suChinese.append(CNUMBERS[x]);
|
||||
suChinese.append("+");
|
||||
suChinese.append(CNUMBERS[y]);
|
||||
}
|
||||
}
|
||||
else if (randomoperands == 2)
|
||||
{
|
||||
if (x >= y)
|
||||
{
|
||||
result = x - y;
|
||||
suChinese.append(CNUMBERS[x]);
|
||||
suChinese.append("-");
|
||||
suChinese.append(CNUMBERS[y]);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = y - x;
|
||||
suChinese.append(CNUMBERS[y]);
|
||||
suChinese.append("-");
|
||||
suChinese.append(CNUMBERS[x]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = x + y;
|
||||
suChinese.append(CNUMBERS[x]);
|
||||
suChinese.append("+");
|
||||
suChinese.append(CNUMBERS[y]);
|
||||
}
|
||||
suChinese.append("=?@" + result);
|
||||
return suChinese.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.m2pool.gateway.config;
|
||||
|
||||
import com.m2pool.gateway.handler.ValidateCodeHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
|
||||
/**
|
||||
* @Description 路由配置信息
|
||||
* @Date 2024/6/13 9:45
|
||||
* @Author dy
|
||||
*/
|
||||
@Configuration
|
||||
public class RouterFunctionConfiguration {
|
||||
|
||||
@Autowired
|
||||
private ValidateCodeHandler validateCodeHandler;
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Bean
|
||||
public RouterFunction routerFunction()
|
||||
{
|
||||
return RouterFunctions.route(
|
||||
RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
|
||||
validateCodeHandler);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.m2pool.gateway.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.gateway.config.GatewayProperties;
|
||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
||||
import org.springframework.cloud.gateway.support.NameUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
|
||||
import org.springframework.web.reactive.config.WebFluxConfigurer;
|
||||
import springfox.documentation.swagger.web.SwaggerResource;
|
||||
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 聚合系统接口
|
||||
*
|
||||
* @author dy
|
||||
*/
|
||||
@Component
|
||||
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer
|
||||
{
|
||||
/**
|
||||
* Swagger2默认的url后缀
|
||||
*/
|
||||
public static final String SWAGGER2URL = "/v2/api-docs";
|
||||
/**
|
||||
* 网关路由
|
||||
*/
|
||||
@Autowired
|
||||
private RouteLocator routeLocator;
|
||||
|
||||
@Autowired
|
||||
private GatewayProperties gatewayProperties;
|
||||
|
||||
/**
|
||||
* 聚合其他服务接口
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<SwaggerResource> get()
|
||||
{
|
||||
List<SwaggerResource> resourceList = new ArrayList<>();
|
||||
List<String> routes = new ArrayList<>();
|
||||
// 获取网关中配置的route
|
||||
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
|
||||
gatewayProperties.getRoutes().stream()
|
||||
.filter(routeDefinition -> routes
|
||||
.contains(routeDefinition.getId()))
|
||||
.forEach(routeDefinition -> routeDefinition.getPredicates().stream()
|
||||
.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
|
||||
.filter(predicateDefinition -> !"m2pool-auth".equalsIgnoreCase(routeDefinition.getId()))
|
||||
.forEach(predicateDefinition -> resourceList
|
||||
.add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
|
||||
.get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL)))));
|
||||
return resourceList;
|
||||
}
|
||||
|
||||
private SwaggerResource swaggerResource(String name, String location)
|
||||
{
|
||||
SwaggerResource swaggerResource = new SwaggerResource();
|
||||
swaggerResource.setName(name);
|
||||
swaggerResource.setLocation(location);
|
||||
swaggerResource.setSwaggerVersion("2.0");
|
||||
return swaggerResource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry)
|
||||
{
|
||||
/** swagger-ui 地址 */
|
||||
registry.addResourceHandler("/swagger-ui/**")
|
||||
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.m2pool.gateway.config.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ApiKey脚本配置
|
||||
*
|
||||
* @author dy
|
||||
*/
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "security.apikey")
|
||||
public class ApiKeyProperties
|
||||
{
|
||||
/**
|
||||
* ApiKey开关
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 排除路径
|
||||
*/
|
||||
private List<String> matchUrls = new ArrayList<>();
|
||||
|
||||
public Boolean getEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public List<String> getMatchUrls()
|
||||
{
|
||||
return matchUrls;
|
||||
}
|
||||
|
||||
public void setMatchUrls(List<String> matchUrls)
|
||||
{
|
||||
this.matchUrls = matchUrls;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.m2pool.gateway.config.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @Description 验证码配置
|
||||
* @Date 2024/6/14 9:26
|
||||
* @Author dy
|
||||
*/
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "security.captcha")
|
||||
public class CaptchaProperties {
|
||||
|
||||
/**
|
||||
* 验证码开关
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 验证码类型(math 数组计算 char 字符)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
public Boolean getEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.m2pool.gateway.config.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description 放行白名单
|
||||
* @Date 2024/6/12 14:24
|
||||
* @Author dy
|
||||
*/
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "security.ignore")
|
||||
public class IgnoreWhiteProperties
|
||||
{
|
||||
/**
|
||||
* 放行白名单配置,网关不校验此处的白名单
|
||||
*/
|
||||
private List<String> whites = new ArrayList<>();
|
||||
|
||||
public List<String> getWhites()
|
||||
{
|
||||
return whites;
|
||||
}
|
||||
|
||||
public void setWhites(List<String> whites)
|
||||
{
|
||||
this.whites = whites;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.m2pool.gateway.config.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* XSS跨站脚本配置
|
||||
*
|
||||
* @author dy
|
||||
*/
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "security.xss")
|
||||
public class XssProperties
|
||||
{
|
||||
/**
|
||||
* Xss开关
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 排除路径
|
||||
*/
|
||||
private List<String> excludeUrls = new ArrayList<>();
|
||||
|
||||
public Boolean getEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public List<String> getExcludeUrls()
|
||||
{
|
||||
return excludeUrls;
|
||||
}
|
||||
|
||||
public void setExcludeUrls(List<String> excludeUrls)
|
||||
{
|
||||
this.excludeUrls = excludeUrls;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
package com.m2pool.gateway.filter;
|
||||
|
||||
import com.m2pool.common.core.constant.*;
|
||||
import com.m2pool.common.core.text.Convert;
|
||||
import com.m2pool.common.core.utils.OpenApiJwtUtils;
|
||||
import com.m2pool.common.core.utils.ServletUtils;
|
||||
import com.m2pool.common.core.utils.StringUtils;
|
||||
import com.m2pool.common.core.utils.ip.IpUtils;
|
||||
import com.m2pool.common.redis.service.RedisService;
|
||||
import com.m2pool.gateway.config.properties.ApiKeyProperties;
|
||||
import com.m2pool.system.api.model.OpenApiKeyInfo;
|
||||
import io.jsonwebtoken.Claims;
|
||||
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.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @Description apiKey鉴权
|
||||
* @Date 2024/6/12 14:13
|
||||
* @Author dy
|
||||
*/
|
||||
@Component
|
||||
public class ApiKeyFilter implements GlobalFilter,Ordered
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiKeyFilter.class);
|
||||
|
||||
private static final Map<String, AtomicInteger> dayLimitCounter = new ConcurrentHashMap<>();
|
||||
private static final Map<String, AtomicInteger> secondLimitCounter = new ConcurrentHashMap<>();
|
||||
private static final int MAX_REQUESTS_SECOND = 5;
|
||||
private static final int MAX_REQUESTS_DAY = 5000;
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
@Autowired
|
||||
private ApiKeyProperties apiKeyProperties;
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||
{
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
ServerHttpRequest.Builder mutate = request.mutate();
|
||||
|
||||
String url = request.getURI().getPath();
|
||||
|
||||
// 跳过不需要验证的路径 只验证/oapi/** 对应的接口
|
||||
if (!StringUtils.matches(url, apiKeyProperties.getMatchUrls()))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
String jwtApiKey = getApiKey(request);
|
||||
System.out.println("API-KEY:"+jwtApiKey);
|
||||
if (StringUtils.isEmpty(jwtApiKey))
|
||||
{
|
||||
return unauthorizedResponse(exchange, "api-key不能为空");
|
||||
}
|
||||
Claims claims = OpenApiJwtUtils.parseApiKey(jwtApiKey);
|
||||
System.out.println("API-KEY解析的身份信息:"+claims);
|
||||
if (claims == null)
|
||||
{
|
||||
System.out.println("claim null");
|
||||
return unauthorizedResponse(exchange, "api-key已过期或格式不正确!",HttpStatus.TOKENEXPIRES);
|
||||
}
|
||||
String apiKey = OpenApiJwtUtils.getApiKey(claims);
|
||||
boolean isSign = redisService.hasKey(getApiKeyRedisKey(apiKey));
|
||||
if (!isSign)
|
||||
{
|
||||
return unauthorizedResponse(exchange, "api-key已过期",HttpStatus.LOGINEXPIRES);
|
||||
}
|
||||
|
||||
OpenApiKeyInfo info = redisService.getCacheObject(getApiKeyRedisKey(apiKey));
|
||||
String apiIp = info.getApiIp();
|
||||
System.out.println("绑定的ip:"+apiIp);
|
||||
String username = OpenApiJwtUtils.getUserName(claims);
|
||||
if (StringUtils.isEmpty(apiIp) || StringUtils.isEmpty(username))
|
||||
{
|
||||
return unauthorizedResponse(exchange, "api-key验证失败");
|
||||
}
|
||||
|
||||
//todo 验证ip
|
||||
String ip = getIP(request);
|
||||
System.out.println("当前ip:"+ip);
|
||||
if(!ip.contains(apiIp)){
|
||||
return unauthorizedResponse(exchange, "当前ip与API-KEY绑定的ip不一致");
|
||||
}
|
||||
//AtomicInteger counter = dayLimitCounter.get(apiKey);
|
||||
//if (counter == null) {
|
||||
// counter = new AtomicInteger(0);
|
||||
// dayLimitCounter.put(apiKey, counter);
|
||||
//}
|
||||
////判断当前分钟
|
||||
//
|
||||
//if (counter.incrementAndGet() > MAX_REQUESTS_DAY) {
|
||||
// return unauthorizedResponse(exchange, "Too many requests from this api-key",HttpStatus.TOO_MANY_REQUESTS);
|
||||
//}
|
||||
|
||||
// 设置用户信息到请求
|
||||
addHeader(mutate, OpenApiKeyConstants.API_KEY, apiKey);
|
||||
addHeader(mutate, OpenApiKeyConstants.API_IP, apiIp);
|
||||
addHeader(mutate, OpenApiKeyConstants.API_USER, username);
|
||||
// 内部请求来源参数清除
|
||||
removeHeader(mutate, OpenApiKeyConstants.FROM_SOURCE);
|
||||
System.out.println("ApiKeyFilter走到最后了");
|
||||
return chain.filter(exchange.mutate().request(mutate.build()).build());
|
||||
}
|
||||
|
||||
private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
String valueStr = value.toString();
|
||||
String valueEncode = ServletUtils.urlEncode(valueStr);
|
||||
mutate.header(name, valueEncode);
|
||||
}
|
||||
|
||||
private void removeHeader(ServerHttpRequest.Builder mutate, String name)
|
||||
{
|
||||
mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
|
||||
}
|
||||
|
||||
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg)
|
||||
{
|
||||
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg,int code)
|
||||
{
|
||||
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存key
|
||||
*/
|
||||
private String getApiKeyRedisKey(String apiKey)
|
||||
{
|
||||
return CacheConstants.OPEN_API_KEY + apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求token
|
||||
*/
|
||||
private String getApiKey(ServerHttpRequest request)
|
||||
{
|
||||
String apiKey = request.getHeaders().getFirst(TokenConstants.API_KEY);
|
||||
// 如果前端设置了令牌前缀,则裁剪掉前缀
|
||||
//if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
|
||||
//{
|
||||
// token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
|
||||
//}
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder()
|
||||
{
|
||||
return -101;
|
||||
}
|
||||
|
||||
// 多次反向代理后会有多个ip值 的分割符
|
||||
private final static String IP_UTILS_FLAG = ",";
|
||||
// 未知IP
|
||||
private final static String UNKNOWN = "unknown";
|
||||
// 本地 IP
|
||||
private final static String LOCALHOST_IP = "0:0:0:0:0:0:0:1";
|
||||
private final static String LOCALHOST_IP1 = "127.0.0.1";
|
||||
|
||||
private static String getIP(ServerHttpRequest request){
|
||||
// 根据 HttpHeaders 获取 请求 IP地址
|
||||
String ip = request.getHeaders().getFirst("X-Forwarded-For");
|
||||
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeaders().getFirst("x-forwarded-for");
|
||||
if (ip != null && ip.length() != 0 && !UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
|
||||
if (ip.contains(IP_UTILS_FLAG)) {
|
||||
ip = ip.split(IP_UTILS_FLAG)[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeaders().getFirst("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeaders().getFirst("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeaders().getFirst("HTTP_CLIENT_IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeaders().getFirst("HTTP_X_FORWARDED_FOR");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeaders().getFirst("X-Real-IP");
|
||||
}
|
||||
//兼容k8s集群获取ip
|
||||
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddress().getAddress().getHostAddress();
|
||||
if (LOCALHOST_IP1.equalsIgnoreCase(ip) || LOCALHOST_IP.equalsIgnoreCase(ip)) {
|
||||
//根据网卡取本机配置的IP
|
||||
InetAddress iNet = null;
|
||||
try {
|
||||
iNet = InetAddress.getLocalHost();
|
||||
} catch (UnknownHostException e) {
|
||||
log.error("getClientIp error: ", e);
|
||||
}
|
||||
ip = iNet.getHostAddress();
|
||||
}
|
||||
}
|
||||
if(StringUtils.isNull(ip)){
|
||||
ip="";
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
package com.m2pool.gateway.filter;
|
||||
|
||||
import com.m2pool.common.core.constant.CacheConstants;
|
||||
import com.m2pool.common.core.constant.HttpStatus;
|
||||
import com.m2pool.common.core.constant.SecurityConstants;
|
||||
import com.m2pool.common.core.constant.TokenConstants;
|
||||
import com.m2pool.common.core.utils.JwtUtils;
|
||||
import com.m2pool.common.core.utils.ServletUtils;
|
||||
import com.m2pool.common.core.utils.StringUtils;
|
||||
import com.m2pool.common.redis.service.RedisService;
|
||||
import com.m2pool.gateway.config.properties.IgnoreWhiteProperties;
|
||||
import io.jsonwebtoken.Claims;
|
||||
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.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @Description 网关鉴权
|
||||
* @Date 2024/6/12 14:13
|
||||
* @Author dy
|
||||
*/
|
||||
@Component
|
||||
public class AuthFilter implements GlobalFilter, Ordered
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
|
||||
|
||||
// 排除过滤的 uri 地址,nacos自行添加
|
||||
@Autowired
|
||||
private IgnoreWhiteProperties ignoreWhite;
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||
{
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
ServerHttpRequest.Builder mutate = request.mutate();
|
||||
|
||||
String url = request.getURI().getPath();
|
||||
// 跳过不需要验证的路径
|
||||
if (StringUtils.matches(url, ignoreWhite.getWhites()))
|
||||
{
|
||||
System.out.println("当前路径在白名单,路径:"+url);
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
String token = getToken(request);
|
||||
System.out.println("token:"+token);
|
||||
if (StringUtils.isEmpty(token))
|
||||
{
|
||||
return unauthorizedResponse(exchange, "令牌不能为空");
|
||||
}
|
||||
Claims claims = JwtUtils.parseToken(token);
|
||||
System.out.println("身份信息:"+claims);
|
||||
if (claims == null)
|
||||
{
|
||||
return unauthorizedResponse(exchange, "令牌已过期或验证不正确!",HttpStatus.TOKENEXPIRES);
|
||||
}
|
||||
String userkey = JwtUtils.getUserKey(claims);
|
||||
System.out.println("userKey"+userkey);
|
||||
boolean islogin = redisService.hasKey(getTokenKey(userkey));
|
||||
if (!islogin)
|
||||
{
|
||||
return unauthorizedResponse(exchange, "登录状态已过期",HttpStatus.LOGINEXPIRES);
|
||||
}
|
||||
String userid = JwtUtils.getUserId(claims);
|
||||
String username = JwtUtils.getUserName(claims);
|
||||
if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))
|
||||
{
|
||||
return unauthorizedResponse(exchange, "令牌验证失败");
|
||||
}
|
||||
|
||||
// 设置用户信息到请求
|
||||
addHeader(mutate, SecurityConstants.USER_KEY, userkey);
|
||||
addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid);
|
||||
addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username);
|
||||
// 内部请求来源参数清除
|
||||
removeHeader(mutate, SecurityConstants.FROM_SOURCE);
|
||||
return chain.filter(exchange.mutate().request(mutate.build()).build());
|
||||
}
|
||||
|
||||
private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
String valueStr = value.toString();
|
||||
String valueEncode = ServletUtils.urlEncode(valueStr);
|
||||
mutate.header(name, valueEncode);
|
||||
}
|
||||
|
||||
private void removeHeader(ServerHttpRequest.Builder mutate, String name)
|
||||
{
|
||||
mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
|
||||
}
|
||||
|
||||
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg)
|
||||
{
|
||||
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg,int code)
|
||||
{
|
||||
System.out.println("111 [鉴权异常处理]请求路径:"+exchange.getRequest().getPath());
|
||||
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
|
||||
System.out.println("222 [鉴权异常处理]请求路径:"+exchange.getRequest().getPath());
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存key
|
||||
*/
|
||||
private String getTokenKey(String token)
|
||||
{
|
||||
return CacheConstants.LOGIN_TOKEN_KEY + token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求token
|
||||
*/
|
||||
private String getToken(ServerHttpRequest request)
|
||||
{
|
||||
String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
|
||||
// 如果前端设置了令牌前缀,则裁剪掉前缀
|
||||
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
|
||||
{
|
||||
token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder()
|
||||
{
|
||||
return -200;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.m2pool.gateway.filter;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description 获取body请求数据(解决流不能重复读取问题)
|
||||
* @Date 2024/6/14 10:31
|
||||
* @Author dy
|
||||
*/
|
||||
@Component
|
||||
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config> {
|
||||
|
||||
static class Config
|
||||
{
|
||||
private Integer order;
|
||||
|
||||
public Integer getOrder()
|
||||
{
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder(Integer order)
|
||||
{
|
||||
this.order = order;
|
||||
}
|
||||
}
|
||||
|
||||
public CacheRequestFilter()
|
||||
{
|
||||
super(Config.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "CacheRequestFilter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public GatewayFilter apply(Config config)
|
||||
{
|
||||
CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter();
|
||||
Integer order = config.getOrder();
|
||||
if (order == null)
|
||||
{
|
||||
return cacheRequestGatewayFilter;
|
||||
}
|
||||
return new OrderedGatewayFilter(cacheRequestGatewayFilter, order);
|
||||
}
|
||||
|
||||
public static class CacheRequestGatewayFilter implements GatewayFilter
|
||||
{
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||
{
|
||||
// GET DELETE 不过滤
|
||||
HttpMethod method = exchange.getRequest().getMethod();
|
||||
if (method == null || method.matches("GET") || method.matches("DELETE"))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
return DataBufferUtils.join(exchange.getRequest().getBody()).map(dataBuffer -> {
|
||||
byte[] bytes = new byte[dataBuffer.readableByteCount()];
|
||||
dataBuffer.read(bytes);
|
||||
DataBufferUtils.release(dataBuffer);
|
||||
return bytes;
|
||||
}).defaultIfEmpty(new byte[0]).flatMap(bytes -> {
|
||||
DataBufferFactory dataBufferFactory = exchange.getResponse().bufferFactory();
|
||||
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest())
|
||||
{
|
||||
@Override
|
||||
public Flux<DataBuffer> getBody()
|
||||
{
|
||||
if (bytes.length > 0)
|
||||
{
|
||||
return Flux.just(dataBufferFactory.wrap(bytes));
|
||||
}
|
||||
return Flux.empty();
|
||||
}
|
||||
};
|
||||
return chain.filter(exchange.mutate().request(decorator).build());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> shortcutFieldOrder()
|
||||
{
|
||||
return Collections.singletonList("order");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.m2pool.gateway.filter;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.m2pool.common.core.utils.ServletUtils;
|
||||
import com.m2pool.common.core.utils.StringUtils;
|
||||
//import com.m2pool.gateway.com.m2pool.common.swagger.config.properties.CaptchaProperties;
|
||||
//import com.m2pool.gateway.com.m2pool.chat.service.ValidateCodeService;
|
||||
import com.m2pool.gateway.config.properties.CaptchaProperties;
|
||||
import com.m2pool.gateway.service.ValidateCodeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @Description 验证码过滤器
|
||||
* @Date 2024/6/13 10:45
|
||||
* @Author dy
|
||||
*/
|
||||
@Component
|
||||
public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> {
|
||||
|
||||
//private final static String[] VALIDATE_URL = new String[] { "/auth/login", "/auth/register" };
|
||||
|
||||
private final static String[] VALIDATE_URL = new String[] {};//邮箱使用邮件发送验证
|
||||
|
||||
@Autowired
|
||||
private ValidateCodeService validateCodeService;
|
||||
|
||||
@Autowired
|
||||
private CaptchaProperties captchaProperties;
|
||||
|
||||
private static final String CODE = "code";
|
||||
|
||||
private static final String UUID = "uuid";
|
||||
|
||||
@Override
|
||||
public GatewayFilter apply(Object config)
|
||||
{
|
||||
return (exchange, chain) -> {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
|
||||
// 非登录/注册请求或验证码关闭,不处理
|
||||
if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled())
|
||||
{
|
||||
//System.out.println(request.getURI().getPath());
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
String rspStr = resolveBodyFromRequest(request);
|
||||
JSONObject obj = JSONObject.parseObject(rspStr);
|
||||
validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage());
|
||||
}
|
||||
return chain.filter(exchange);
|
||||
};
|
||||
}
|
||||
|
||||
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest)
|
||||
{
|
||||
// 获取请求体
|
||||
Flux<DataBuffer> body = serverHttpRequest.getBody();
|
||||
AtomicReference<String> bodyRef = new AtomicReference<>();
|
||||
body.subscribe(buffer -> {
|
||||
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
|
||||
DataBufferUtils.release(buffer);
|
||||
bodyRef.set(charBuffer.toString());
|
||||
});
|
||||
return bodyRef.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.m2pool.gateway.filter;
|
||||
|
||||
import com.m2pool.common.core.utils.StringUtils;
|
||||
import com.m2pool.common.core.utils.html.EscapeUtil;
|
||||
import com.m2pool.gateway.config.properties.XssProperties;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
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.*;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 跨站脚本过滤器
|
||||
*
|
||||
* @author dy
|
||||
*/
|
||||
@Component
|
||||
@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true")
|
||||
public class XssFilter implements GlobalFilter, Ordered
|
||||
{
|
||||
// 跨站脚本的 xss 配置,nacos自行添加
|
||||
@Autowired
|
||||
private XssProperties xss;
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||
{
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
// GET DELETE 不过滤
|
||||
HttpMethod method = request.getMethod();
|
||||
if (method == null || method.matches("GET") || method.matches("DELETE"))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
// 非json类型,不过滤
|
||||
if (!isJsonRequest(exchange))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
// excludeUrls 不过滤
|
||||
String url = request.getURI().getPath();
|
||||
if (StringUtils.matches(url, xss.getExcludeUrls()))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange);
|
||||
return chain.filter(exchange.mutate().request(httpRequestDecorator).build());
|
||||
|
||||
}
|
||||
|
||||
private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange)
|
||||
{
|
||||
ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest())
|
||||
{
|
||||
@Override
|
||||
public Flux<DataBuffer> getBody()
|
||||
{
|
||||
Flux<DataBuffer> body = super.getBody();
|
||||
return body.buffer().map(dataBuffers -> {
|
||||
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
|
||||
DataBuffer join = dataBufferFactory.join(dataBuffers);
|
||||
byte[] content = new byte[join.readableByteCount()];
|
||||
join.read(content);
|
||||
DataBufferUtils.release(join);
|
||||
String bodyStr = new String(content, StandardCharsets.UTF_8);
|
||||
// 防xss攻击过滤
|
||||
bodyStr = EscapeUtil.clean(bodyStr);
|
||||
// 转成字节
|
||||
byte[] bytes = bodyStr.getBytes();
|
||||
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
|
||||
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
|
||||
buffer.write(bytes);
|
||||
return buffer;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders()
|
||||
{
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.putAll(super.getHeaders());
|
||||
// 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
|
||||
httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
|
||||
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
};
|
||||
return serverHttpRequestDecorator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是Json请求
|
||||
*
|
||||
* @param exchange HTTP请求
|
||||
*/
|
||||
public boolean isJsonRequest(ServerWebExchange exchange)
|
||||
{
|
||||
String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
||||
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder()
|
||||
{
|
||||
return -100;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.m2pool.gateway.handler;
|
||||
|
||||
import com.m2pool.common.core.utils.ServletUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
|
||||
import org.springframework.cloud.gateway.support.NotFoundException;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @Description 网关统一异常处理
|
||||
* @Date 2024/6/14 10:09
|
||||
* @Author dy
|
||||
*/
|
||||
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
|
||||
if (exchange.getResponse().isCommitted())
|
||||
{
|
||||
return Mono.error(ex);
|
||||
}
|
||||
|
||||
String msg;
|
||||
|
||||
if (ex instanceof NotFoundException)
|
||||
{
|
||||
msg = "服务未找到";
|
||||
}
|
||||
else if (ex instanceof ResponseStatusException)
|
||||
{
|
||||
ResponseStatusException responseStatusException = (ResponseStatusException) ex;
|
||||
msg = responseStatusException.getMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = "内部服务器错误";
|
||||
}
|
||||
|
||||
log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
|
||||
|
||||
return ServletUtils.webFluxResponseWriter(response, msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.m2pool.gateway.handler;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.m2pool.common.core.utils.ServletUtils;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebExceptionHandler;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @Description 自定义限流异常处理
|
||||
* @Date 2024/6/14 10:07
|
||||
* @Author dy
|
||||
*/
|
||||
public class SentinelFallbackHandler implements WebExceptionHandler {
|
||||
|
||||
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange)
|
||||
{
|
||||
|
||||
ServerHttpResponse serverHttpResponse = exchange.getResponse();
|
||||
serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
|
||||
|
||||
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍候再试");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
|
||||
if (exchange.getResponse().isCommitted())
|
||||
{
|
||||
return Mono.error(ex);
|
||||
}
|
||||
if (!BlockException.isBlockException(ex))
|
||||
{
|
||||
return Mono.error(ex);
|
||||
}
|
||||
return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
|
||||
|
||||
}
|
||||
|
||||
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable)
|
||||
{
|
||||
return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.m2pool.gateway.handler;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Mono;
|
||||
import springfox.documentation.swagger.web.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/swagger-resources")
|
||||
public class SwaggerHandler
|
||||
{
|
||||
@Autowired(required = false)
|
||||
private SecurityConfiguration securityConfiguration;
|
||||
|
||||
@Autowired(required = false)
|
||||
private UiConfiguration uiConfiguration;
|
||||
|
||||
private final SwaggerResourcesProvider swaggerResources;
|
||||
|
||||
@Autowired
|
||||
public SwaggerHandler(SwaggerResourcesProvider swaggerResources)
|
||||
{
|
||||
this.swaggerResources = swaggerResources;
|
||||
}
|
||||
|
||||
@GetMapping("/configuration/security")
|
||||
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration()
|
||||
{
|
||||
return Mono.just(new ResponseEntity<>(
|
||||
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
|
||||
HttpStatus.OK));
|
||||
}
|
||||
|
||||
@GetMapping("/configuration/ui")
|
||||
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration()
|
||||
{
|
||||
return Mono.just(new ResponseEntity<>(
|
||||
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@GetMapping("")
|
||||
public Mono<ResponseEntity> swaggerResources()
|
||||
{
|
||||
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.m2pool.gateway.handler;
|
||||
|
||||
import com.m2pool.common.core.exception.CaptchaException;
|
||||
import com.m2pool.common.core.web.Result.AjaxResult;
|
||||
import com.m2pool.gateway.service.ValidateCodeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @Description 验证码获取
|
||||
* @Date 2024/6/13 10:22
|
||||
* @Author dy
|
||||
*/
|
||||
@Component
|
||||
public class ValidateCodeHandler implements HandlerFunction<ServerResponse> {
|
||||
|
||||
@Autowired
|
||||
private ValidateCodeService validateCodeService;
|
||||
|
||||
@Override
|
||||
public Mono<ServerResponse> handle(ServerRequest request) {
|
||||
AjaxResult ajax;
|
||||
try
|
||||
{
|
||||
ajax = validateCodeService.createCaptcha();
|
||||
}
|
||||
catch (CaptchaException | IOException e)
|
||||
{
|
||||
return Mono.error(e);
|
||||
}
|
||||
return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.m2pool.gateway.service;
|
||||
|
||||
import com.m2pool.common.core.exception.CaptchaException;
|
||||
import com.m2pool.common.core.web.Result.AjaxResult;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @Description 验证码处理
|
||||
* @Date 2024/6/13 9:16
|
||||
* @Author dy
|
||||
*/
|
||||
public interface ValidateCodeService {
|
||||
|
||||
/**
|
||||
* 生成验证码
|
||||
*/
|
||||
public AjaxResult createCaptcha() throws IOException, CaptchaException;
|
||||
|
||||
/**
|
||||
* 校验验证码
|
||||
*/
|
||||
public void checkCaptcha(String key, String value) throws CaptchaException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.m2pool.gateway.service.impl;
|
||||
|
||||
|
||||
import com.google.code.kaptcha.Producer;
|
||||
import com.m2pool.common.core.constant.Constants;
|
||||
import com.m2pool.common.core.exception.CaptchaException;
|
||||
import com.m2pool.common.core.utils.StringUtils;
|
||||
import com.m2pool.common.core.utils.sign.Base64;
|
||||
import com.m2pool.common.core.utils.uuid.IdUtils;
|
||||
import com.m2pool.common.core.web.Result.AjaxResult;
|
||||
import com.m2pool.common.redis.service.RedisService;
|
||||
import com.m2pool.gateway.config.properties.CaptchaProperties;
|
||||
import com.m2pool.gateway.service.ValidateCodeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.FastByteArrayOutputStream;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @Description 验证码业务处理
|
||||
* @Date 2024/6/13 9:17
|
||||
* @Author dy
|
||||
*/
|
||||
@Service
|
||||
public class ValidateCodeServiceImpl implements ValidateCodeService {
|
||||
|
||||
@Resource(name = "captchaProducer")
|
||||
private Producer captchaProducer;
|
||||
|
||||
@Resource(name = "captchaProducerMath")
|
||||
private Producer captchaProducerMath;
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Autowired
|
||||
private CaptchaProperties captchaProperties;
|
||||
|
||||
|
||||
/**
|
||||
* 生成验证码
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult createCaptcha() throws IOException, CaptchaException {
|
||||
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
|
||||
boolean captchaOnOff = captchaProperties.getEnabled();
|
||||
|
||||
ajax.put("captchaOnOff", captchaOnOff);
|
||||
|
||||
if (!captchaOnOff)
|
||||
{
|
||||
return ajax;
|
||||
}
|
||||
|
||||
// 保存验证码信息
|
||||
String uuid = IdUtils.simpleUUID();
|
||||
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
|
||||
|
||||
String capStr = null, code = null;
|
||||
BufferedImage image = null;
|
||||
|
||||
String captchaType = captchaProperties.getType();
|
||||
// 生成验证码
|
||||
if ("math".equals(captchaType))
|
||||
{
|
||||
String capText = captchaProducerMath.createText();
|
||||
capStr = capText.substring(0, capText.lastIndexOf("@"));
|
||||
code = capText.substring(capText.lastIndexOf("@") + 1);
|
||||
image = captchaProducerMath.createImage(capStr);
|
||||
}
|
||||
else if ("char".equals(captchaType))
|
||||
{
|
||||
capStr = code = captchaProducer.createText();
|
||||
image = captchaProducer.createImage(capStr);
|
||||
}
|
||||
|
||||
redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
||||
// 转换流信息写出
|
||||
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
|
||||
try
|
||||
{
|
||||
ImageIO.write(image, "jpg", os);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
ajax.put("uuid", uuid);
|
||||
ajax.put("img", Base64.encode(os.toByteArray()));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCaptcha(String code, String uuid) throws CaptchaException {
|
||||
|
||||
if (StringUtils.isEmpty(code))
|
||||
{
|
||||
throw new CaptchaException("验证码不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(uuid))
|
||||
{
|
||||
throw new CaptchaException("验证码已失效");
|
||||
}
|
||||
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
|
||||
String captcha = redisService.getCacheObject(verifyKey);
|
||||
redisService.deleteObject(verifyKey);
|
||||
|
||||
if (!code.equalsIgnoreCase(captcha))
|
||||
{
|
||||
throw new CaptchaException("验证码错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
100
m2pool-gateway/src/main/resources/bootstrap.yml
Normal file
100
m2pool-gateway/src/main/resources/bootstrap.yml
Normal file
@@ -0,0 +1,100 @@
|
||||
# Tomcat
|
||||
server:
|
||||
port: 8201
|
||||
# Spring
|
||||
spring:
|
||||
application:
|
||||
# 应用名称
|
||||
name: m2pool-gateway
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: prod
|
||||
main:
|
||||
allow-circular-references: true
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8808
|
||||
namespace: m2_prod
|
||||
group: m2_prod_group
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8808
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
namespace: m2_prod
|
||||
group: m2_prod_group
|
||||
sentinel:
|
||||
# 取消控制台懒加载
|
||||
eager: true
|
||||
transport:
|
||||
# 控制台地址
|
||||
dashboard: 127.0.0.1:8718
|
||||
# nacos配置持久化
|
||||
datasource:
|
||||
ds1:
|
||||
nacos:
|
||||
server-addr: 127.0.0.1:8808
|
||||
dataId: sentinel-m2pool-gateway
|
||||
groupId: m2_prod_group
|
||||
data-type: json
|
||||
rule-type: flow
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 2MB
|
||||
max-request-size: 8MB
|
||||
|
||||
#server:
|
||||
# port: 8101
|
||||
## Spring
|
||||
#spring:
|
||||
# application:
|
||||
# # 应用名称
|
||||
# name: m2pool-gateway
|
||||
# profiles:
|
||||
# # 环境配置
|
||||
# active: test
|
||||
# main:
|
||||
# allow-circular-references: true
|
||||
# allow-bean-definition-overriding: true
|
||||
#
|
||||
# cloud:
|
||||
# nacos:
|
||||
# discovery:
|
||||
# server-addr: 127.0.0.1:8808
|
||||
# namespace: m2_test
|
||||
# group: m2_test_group
|
||||
# config:
|
||||
# # 配置中心地址
|
||||
# server-addr: 127.0.0.1:8808
|
||||
# # 配置文件格式
|
||||
# file-extension: yml
|
||||
# # 共享配置
|
||||
# shared-configs:
|
||||
# - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
# namespace: m2_test
|
||||
# group: m2_test_group
|
||||
# sentinel:
|
||||
# # 取消控制台懒加载
|
||||
# eager: true
|
||||
# transport:
|
||||
# # 控制台地址
|
||||
# dashboard: 127.0.0.1:8718
|
||||
# # nacos配置持久化
|
||||
# datasource:
|
||||
# ds1:
|
||||
# nacos:
|
||||
# server-addr: 127.0.0.1:8808
|
||||
# dataId: sentinel-m2pool-gateway
|
||||
# groupId: m2_test_group
|
||||
# data-type: json
|
||||
# rule-type: flow
|
||||
# servlet:
|
||||
# multipart:
|
||||
# max-file-size: 2MB
|
||||
# max-request-size: 8MB
|
||||
74
m2pool-gateway/src/main/resources/logback.xml
Normal file
74
m2pool-gateway/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<!-- 日志存放路径 -->
|
||||
<property name="log.path" value="logs/m2pool-gateway" />
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 单位:天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.m2pool" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info" />
|
||||
<appender-ref ref="file_error" />
|
||||
</root>
|
||||
</configuration>
|
||||
BIN
m2pool-gateway/src/main/resources/nginx-selfsigned.pfx
Normal file
BIN
m2pool-gateway/src/main/resources/nginx-selfsigned.pfx
Normal file
Binary file not shown.
Reference in New Issue
Block a user