Spring Cloud初探之spring cloud gateway实现转发、鉴权及负载均衡(六)
背景
本篇是Spring cloud alibaba组件研究第六篇。描述如何通过spring cloud gateway组件实现路由转发,鉴权和自定义负载均衡。
搭建微服务框架时可以在前端放置一个nginx做代理,静态资源(html、css、js等)放置到nginx的html文件夹下,后端请求转发到gateway处理。如下图所示:
引入依赖的包
Spring cloud gateway不是一个独立可部署的组件,使用时需要创建一个Java工程做好配置后再打包部署。
这里把gateway组件作为一个服务注册到nacos, 并通过loadbbalance做负载均衡,引入如下依赖:
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
同时通过JWT在网关做认证鉴权,引入JWT的包:
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.14.0</version></dependency>
最后引入spring cloud gateway的包:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>
Spring cloud的版本在父pom文件中指定,不再赘述。详细代码可以查看文末的github仓库地址。
配置路由转发策略
Spring cloud gateway的路径转发策略很丰富,可以参看Spring cloud的官方文档。Demo样式仅配置一个常用的Path转发策略:
spring:gateway:routes:- id: cloud-server-oneuri: lb://cloud-server-one#uri: http://localhost:19527/spring-cloud-serverpredicates:- Path=/cloud-server-one/**
配置转发URI可以写具体的地址,也可以配置注册到nacos的服务名。使用服务名更灵活,方便后续使用自定义负载均衡策略调度。
使用过滤器拦截请求做认证鉴权
由于Spring cloud gateway使用的是webflux框架,不能用SpringMVC的拦截器。这里通过实现WebFilter接口的方式拦截请求。
package com.neo.springcloud.gateway.service;import com.neo.springcloud.gateway.util.JWTUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
import reactor.core.publisher.Mono;/*** 权限认证服务** @author neo* @since 2025/5/12* @version 1.0*/
@Component
public class AuthorityService implements WebFilter {private static final Logger LOGGER = LogManager.getLogger(AuthorityService.class);private static PathPattern loginPattern = PathPatternParser.defaultInstance.parse("/spring-cloud-one/v1/login/**");@Value("${gateway.jwt.secret:}")private String jwtSecret;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {/*** 登录接口不做鉴权*/if (loginPattern.matches(exchange.getRequest().getPath())) {return chain.filter(exchange);}// 提取请求头中的jwt信息HttpHeaders headers = exchange.getRequest().getHeaders();String jwtToken = headers.getFirst("jwt-token");try {// 在此处对JWT的合法性校验JWTUtil.instance().verifyJWT(jwtToken, jwtSecret);} catch (Exception e){LOGGER.error("Verify token fail.", e);ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.UNAUTHORIZED);return Mono.empty();}/*** 下面还可以补充对用户的其它权限校验。可以解析出用户的姓名,账号等非敏感信息放到header中,下游接口可以直接获取使用*/return chain.filter(exchange);}
}
-
上述代码对登录接口放行。如果有多个接口需要放行,或者基于用户的角色对部分接口放行(例如:游客身份的用户可以体验部分功能),可以将这部分代码提到单独的类或者方法中实现。
-
上述代码仅用JWT对用户的身份做了认证。如果要做更细致的鉴权处理,可以放在下面代码注释部分。注意:过滤器的代码会频繁执行,用户的权限信息可以放到redis中缓存,提升鉴权处理效率。
自定义负载均衡策略
自定义负载均衡策略的代码可以参考前面的文章《Spring Cloud初探之自定义负载均衡策略(五)》。完整代码从文末的github仓库地址获取。
打包部署gateway
使用mvn打包Spring cloud gateway项目,跟启动java项目一样启动服务。
源码地址: https://github.com/ylforever/neo-spring-cloud-server