SpringCloud:网关gateway(单点登录)

发布时间:2022-08-18 18:34

一、简介

网关是一个服务:
Spring Cloud GateWay是Spring Cloud的⼀个全新项⽬,⽬标是取代Netflix Zuul,基于Spring5.0+SpringBoot2.0+WebFlux(基于⾼性能的Reactor模式响应式通信框架Netty,异步⾮阻塞模型)等技术开发,性能⾼于Zuul,官⽅测试,GateWay是Zuul的1.6倍,旨在为微服务架构提供⼀种简单有效的统⼀的API路由管理⽅式。

二、开始使用

1.引入包(gateway)        



	org.springframework.cloud
	spring-cloud-starter-gateway



	org.springframework.cloud
	spring-cloud-starter-loadbalancer

2. 配置nacos进行服务注册和发现

        描述:使用nacos+gateway实现各模块服务的负载均衡

        nacos的配置使用可以参考文章:

        SpringCloud:注册中心nacos_Cx_轩的博客-CSDN博客

3..yml配置

spring:
  application:
    name: Cx-gateway
  cloud:
    gateway:
      httpclient:
        connect-timeout: 90000  #连接超时 毫秒
        response-timeout: 90s #应答超时 java.time.Duration http状态码504
      discovery:
        locator:
          enabled: false # 启用探测器 默认false,开启后可以通过ip:port/服务名称/接口地址进行服务转发 
          lower-case-service-id: true # 路由名小写
      routes:
        - id: Cx-admin # admin后台
          uri: lb://Cx-admin
          predicates:
            - Path=/admin/**
          filters:
            - StripPrefix=1   # 过滤前缀 admin
        - id: Cx-es # es服务
          uri: lb://Cx-es
          predicates:
            - Path=/es/**
          filters:
            - StripPrefix=1   # 过滤前缀 es

此处对predicates断言进行使用描述:(常用的几种列举出来方便大家参考)

1.Path路径断言
predicates:

        -Path=/xx  # 拦截此路径下的所有请求发送到网关配置的uri (以一个模块一个路径去区分)
2.Query断言
predicates:

        -Query=name,age.  #参数值可以写正则,也可以只写参数名
3.Method断言
predicates:

        -Method=get 
4.Host断言
predicates:

        -Host=xxxx.com
5.Cookie断言
predicates:

        -Cookie=user,Cx #cookie断言和上面介绍的几种断言方式都大同小异,唯一不同的是他必须连同属性值一起验证,不能单独只验证属性是否存在
6.Header断言
predicates:

        -Header=id,1234\d+ # 正则表达式\d+ 数字,header断言是检查头信息里是否携带了相关属性或令牌
7.时间路由
predicates:
          - After=2022-02-07T17:05:00.789+08:00[Asia/Shanghai]  # 时间匹配有三种模式,分别是Before、After和Between,指定了在什么时间范围内路由才会生效

三、网关+单点登录使用

1.使用jwt生成无状态token令牌,然后在网关项目中进行auth验证。

2.创建网关全局拦截

@Configuration
@Component
@Slf4j
public class AuthFilter implements GlobalFilter,Ordered {
	
	private static final String AUTHORIZE_TOKEN = "token";

	private static AntPathMatcher matcher = new AntPathMatcher();
	
	@Override
	public int getOrder() {
		return 0;
	}

	@Override
	public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		ServerHttpRequest request = exchange.getRequest();
		String url = request.getPath().toString();
		log.info("【登录拦截】获取请求地址路径:"+url);
		// 不需要拦截的url直接通过
		if(isNotAuth(url)){
			return chain.filter(exchange);
		}
		String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN);
		if(StrUtil.isBlank(token)){
			token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
		}
		if(StrUtil.isBlank(token)){
			log.info("【登录拦截】未获取到token值...");
			loginResponse(exchange);
		}
		log.debug("【登录拦截】获取token值:"+token);
		try {
			SSOToken ssoToken = SSOToken.parser(token);
			// 获取token中的用户名
			String userId = ssoToken.getId();
			log.info("【登录拦截】获取userId:"+userId);
        } catch (Exception e) {
        	log.error("【登录拦截】异常:"+e.getMessage());
            return loginResponse(exchange);
        }
		return chain.filter(exchange);
	}
	
	public static Mono loginResponse(ServerWebExchange exchange) {
        JSONObject json = JSONUtil.createObj();
        json.set("code", 401);
        json.set("msg", "请重新登陆授权");
        ServerHttpResponse response = exchange.getResponse();
        byte[] bytes = JSONUtil.toJsonStr(json).getBytes(StandardCharsets.UTF_8);
        //指定编码,否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
        DataBuffer buffer = response.bufferFactory().wrap(bytes);
        return response.writeWith(Flux.just(buffer));
    }

	private boolean isNotAuth(String url) {
		List uriList = new ArrayList<>();
		// admin后台不需要拦截
        uriList.add("/admin/**");
        uriList.add("/sso/login");
        
        for (String pattern : uriList) {
            if (matcher.match(pattern, url)) {
                // 不需要拦截
                return true;
            }
        }
		return false;
	}
}

上述代码中SSOToken就是jwt的封装,大家可以直接使用jwt进行解析即可。

注:此处使用jwt无状态token令牌,为了方便不同模块、不同前端项目针对不同ip和端口部署的分布式应用时在进行用户验权时可以不需要考虑会话session和cookie只需要将token存储在浏览器中即可全局使用。在访问时只校验token的有效性。所以在使用jwt的token时可以降低token的有效时长在增加安全性。

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号