网关服务
项目结构
pom依赖
1.cloud父项目pom
<modelVersion>4.0.0</modelVersion>
<groupId>com.chen</groupId>
<artifactId>cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<description>Demo project for Spring Boot</description>
<modules>
<module>common</module>
<module>gateway</module>
</modules>
<properties>
<java.version>1.8</java.version>
<boot.version>2.5.2</boot.version>
<maven.version>3.1</maven.version>
<spring-cloud.version>2020.0.4</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
<druid.version>1.2.8</druid.version>
<alibaba.fastjson.version>1.2.83</alibaba.fastjson.version>
<discovery.nacos.version>2.2.0.RELEASE</discovery.nacos.version>
<alibaba.fastjson.version>1.2.83</alibaba.fastjson.version>
<jh-starter.version>2.0.0</jh-starter.version>
<hutool.version>5.7.7</hutool.version>
<spring-data-commons.version>2.4.5</spring-data-commons.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
<jh.jwt.version>0.11.1</jh.jwt.version>
<common.version>0.0.1-SNAPSHOT</common.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Spring Cloud 相关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Spring Cloud Alibaba 相关依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
<version>${discovery.nacos.version}</version>
</dependency>
<dependency>
<groupId>com.chen</groupId>
<artifactId>common</artifactId>
<version>${common.version}</version>
</dependency>
<dependency>
<groupId>com.goodwill</groupId>
<artifactId>goodwill-spring-boot-stater</artifactId>
<version>${jh-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${spring-data-commons.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${alibaba.fastjson.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jh.jwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jh.jwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jh.jwt.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
2.common子项目pom
<modelVersion>4.0.0</modelVersion>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>common</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.chen</groupId>
<artifactId>cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<!-- spring -->
<!-- 工具包 -->
<dependency>
<groupId>com.goodwill</groupId>
<artifactId>goodwill-spring-boot-stater</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.gateway子项目pom
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway</name>
<packaging>jar</packaging>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.chen</groupId>
<artifactId>cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.chen</groupId>
<artifactId>common</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- gateway网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- nacos服务注册与发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
gateway网关服务
1.application.yml
server:
port: 8800
spring:
application:
name: gateway
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: 80a98d11-492c-4008-85aa-32d889e9b0d0
gateway:
globalcors:
corsConfigurations: #跨域设置
'[/**]':
allowCredentials: true
allowedHeaders: '*'
allowedMethods: '*'
allowedOriginPatterns: '*'
discovery:
locator:
enabled: true
enabled: true
routes:
- id: user #用户服务,做用户注册、登录
uri: lb://user
predicates:
- Path=/sso/**
- id: auth #权限服务,做token权限认证
uri: lb://auth
predicates:
- Path=/oauth/**
jh:
jwt:
header: Authorization
tokenPrefix: Bearer
#白名单
gateway:
ignored-urls:
- /oauth/**
- /sso/**
2.创建过滤规则
@Component
@Order(0)
@EnableConfigurationProperties(value = IgnoredUrlsProperties.class)
public class AuthenticationFilter implements GlobalFilter, InitializingBean {
@Value("${jh.jwt.header}")
private String tokenHeader;
@Value("${jh.jwt.tokenPrefix}")
private String tokenPrefix;
//公钥
private PublicKey publicKey;
//白名单
@Autowired
private IgnoredUrlsProperties ignoredUrlsProperties;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String reqUrl = exchange.getRequest().getURI().getPath();
//白名单过滤规则
if (shouldIgnoredUrl(reqUrl)) {
return chain.filter(exchange);
}
String authHeader = exchange.getRequest().getHeaders().getFirst(tokenHeader);
if (StringUtils.isEmpty(authHeader)) {
throw new GateWayException(HttpStatus.AUTHORIZATION_HEADER_IS_EMPTY);
}
//解析请求中的token
String token = StringUtils.getToken(authHeader, tokenPrefix);
//验证token
Claims claims = JwtUtils.validateJwtToken(token, publicKey);
//登录信息存入请求头中
ServerWebExchange webExchange = setHeader(exchange, claims);
return chain.filter(webExchange);
}
private ServerWebExchange setHeader(ServerWebExchange serverWebExchange, Claims claims) {
String loginName = claims.get("userInfo", Map.class).get("loginName").toString();
ServerHttpRequest request = serverWebExchange.getRequest().mutate()
.header("loginName", loginName)
.build();
return serverWebExchange.mutate().request(request).build();
}
private boolean shouldIgnoredUrl(String reqUrl) {
PathMatcher pathMatcher = new AntPathMatcher();
for (String ignoredUrls : ignoredUrlsProperties.getIgnoredUrls()) {
if (pathMatcher.match(ignoredUrls, reqUrl)) {
return true;
}
}
return false;
}
@Override
public void afterPropertiesSet(){
//从认证服务获取publicKey
this.publicKey = JwtUtils.genPublicKey();
}
public class JwtUtils {
public static PublicKey genPublicKey() throws GateWayException {
try {
//从权限服务获取tokenKey
String tokenKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhLgJjSTxZbL6XNYIW/VaMOvFI2DRMFCdpK4XNCviE6z1vg1yFB+LIJuJ6gbVhRfAOW07y1UDiWkup8k5CpEPxvccGyo8wOz0gsHAf6WGCtqqY0War0lv1faiut31niQ05qs6XqzjBWzekad4A2ItZq/SqNnDn9PskWWoO0+PiWy9DSvUsHNQQIaVovzYCiwPQxAU/1CbFIE4DxMuJFVx2Vs36HW8LA3RdStObIuw+3J32G5+1XzetL2hfPj9mQiNIGkei/i6Hpr3X4S8RZhrRVfyIbqGYTKJw7uGTAQdHAF4QvMtHGFiqC3vmkp6M6k7x/HgW+BDWsacetGPkjjiMQIDAQAB";
java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(tokenKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
} catch (Exception e) {
throw new GateWayException(HttpStatus.GEN_PUBLIC_KEY_ERROR);
}
}
public static Claims validateJwtToken(String token, PublicKey publicKey) {
try {
Jwt<JwsHeader, Claims> parseClaimsJwt = Jwts.parser()
.setSigningKey(publicKey).parseClaimsJws(token);
return parseClaimsJwt.getBody();
} catch (Exception e) {
throw new GateWayException(HttpStatus.JWT_TOKEN_EXPIRE);
}
}
}