• 实战讲解网关接口统一认证SpringCloudGateway(图+文)


    1 缘起

    继gateway限流篇:https://blog.csdn.net/Xin_101/article/details/127890605
    之后,继续补充网关统一鉴权的相关应用,
    网关作为所有流量入口,承接所有请求,因此,可以在网关层统一做鉴权,
    授权的放行,未授权的禁行,这里,可以添加黑白名单的功能,
    白名单,无需鉴权,直接放行;
    黑名单,直接禁行,
    本文,即通过实战讲解网关鉴权以及黑白名单的使用。

    2 架构

    整体架构如下图所示,
    由图可知,该体系共有三部分:
    (1)网关层:做统一鉴权,保护后面的服务;
    (2)注册中心层:管理所有服务;
    (3)服务层:业务或其他功能性服务。
    在这里插入图片描述

    3 网关配置

    网关配置的白名单是针对保护的资源,
    当用户访问白名单的资源时,无需鉴权,即直接通过约定,即可获取正确的响应,
    访问非白名单的资源时,需要鉴权成功后,才能获取正确的响应,否则,无法获取正确的响应。

    3.1 白名单配置

    白名单配置有两种方式,
    (1)在启动的文件application.yml中配置;
    (2)在数据库Redis或MySQL中配置,启动应用时,需要将数据加载到内存(JVM),
    如何在SpringBoot启动时加载外部数据到内存参见:https://blog.csdn.net/Xin_101/article/details/127945236
    简单起见,本文直接在配置文件application.yml中配置白名单,
    样例如下:

    request:
      white-list:
        - /api/v1/get/test
    
    • 1
    • 2
    • 3

    3.2 白名单映射的实体

    由上面的配置可知,映射的实体中数据类型为List,
    白名单实体如下图所示,完整样例在图后面。
    在这里插入图片描述

    package com.monkey.gateway_template.config;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * 请求白名单.
     *
     * @author xindaqi
     * @since 2022-11-19 15:23
     */
    @Component
    @ConfigurationProperties("request")
    public class RequestWhiteList {
    
        /**
         * 白名单列表
         */
        List<String> whiteList;
    
        public List<String> getWhiteList() {
            return whiteList;
        }
    
        public void setWhiteList(List<String> whiteList) {
            this.whiteList = whiteList;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3.2 请求链配置

    为了使网关具有统一鉴权的功能,就需要在网关服务中添加请求拦截功能,通过实现GlobalFilter接口来拦截请求。
    测试样例核心如下图所示,核心部分均有注释,源码在图后面。
    这里为了方便测试,在非白名单鉴权时,没有做token校验,只判断是否在请求头中携带token,
    实际应用中开发者自定这部分认证逻辑,比如通过Redis、JWT、Oauth2.0等。

    在这里插入图片描述

    package com.monkey.gateway_template.config;
    
    import com.google.gson.Gson;
    import com.monkey.gateway_template.response.Response;
    import org.apache.http.HttpHeaders;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    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.DataBuffer;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    import javax.annotation.Resource;
    import javax.ws.rs.core.MediaType;
    import java.nio.charset.StandardCharsets;
    import java.util.List;
    import java.util.Objects;
    
    /**
     * 请求拦截器(过滤器).
     *
     * @author xindaqi
     * @since 2022-11-19 15:18
     */
    @Component
    public class RequestFilter implements GlobalFilter, Ordered {
    
        private static final Logger logger = LoggerFactory.getLogger(RequestFilter.class);
    
        private static final String TOKEN = "token";
    
        // 获取配置的白名单
        @Resource
        RequestWhiteList requestWhiteList;
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
            // 获取请求的URI,网关配置uri的lb时做了剪裁,所以,直接使用原生接口的URI,无需拼接其他内容
            String requestPath = exchange.getRequest().getPath().value();
            // 白名单接口直接放行
            if (Objects.nonNull(requestWhiteList) && requestWhiteList.getWhiteList().contains(requestPath)) {
                return chain.filter(exchange);
            }
            // 非白名单接口需要鉴权:请求头携带token
            List<String> tokenList = exchange.getRequest().getHeaders().get(TOKEN);
            // 这里为了方便测试,没有做token校验,只判断是否在请求头中携带token,
            // 实际应用中开发这自定这部分认证逻辑
            if (Objects.isNull(tokenList) || tokenList.size() == 0) {
                Gson gson = new Gson();
                // 这里开发者可以自定义响应的内容,我自己构建的对象Response
                byte[] data = gson.toJson(Response.invalidToken()).getBytes(StandardCharsets.UTF_8);
                ServerHttpResponse response = exchange.getResponse();
                DataBuffer buffer = response.bufferFactory().wrap(data);
                // 状态码配置:未授权401
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
                return response.writeWith(Mono.just(buffer));
            }
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return Ordered.LOWEST_PRECEDENCE;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    4 测试

    准备的测试接口如下:
    接口由其他服务提供,测试使用的为自建的producer服务,原生接口URI如下表所示

    序号状态接口
    1白名单接口/api/v1/get/test
    2非白名单接口/api/v1/biz/test

    producer是通过网关进行访问的,网关和producer均注册到同一个注册中心集群,
    所以无需关注producer的IP和PORT,通过网关已经配置,参见gateway限流篇:https://blog.csdn.net/Xin_101/article/details/127890605
    所以请求时,通过网关的IP和PORT以及配置的断言Path,这里配置的为producer-server,
    所以通过网关请求produer接口时需要添加produer-server前缀。
    为了使限流生效,断言Path切不可与服务名相同。

    4.1 白名单

    白名单接口无需进行授权,直接访问,按照约定数据即可获取正确的数据。
    测试结果如下图所示。
    在这里插入图片描述

    4.2 非白名单

    非白名单接口需要进行鉴权,
    授权通过后,方可获取正确的结果,如果授权失败,则返回未授权相关信息,
    测试结果如下图所示。
    在这里插入图片描述

    5 小结

    • 白名单配置有两种方式,
      (1)在启动的文件application.yml中配置;
      (2)在数据库Redis或MySQL中配置,启动应用时,需要将数据加载到内存(JVM),
      如何在SpringBoot启动时加载外部数据到内存参见:https://blog.csdn.net/Xin_101/article/details/127945236
    • 网关拦截请求核心是实现GlobalFilter接口,重写方法filter(ServerWebExchange exchange, GatewayFilterChain chain)。
  • 相关阅读:
    Win11配置多个CUDA环境
    XSS漏洞DOM型总结、XSS利用、XSS绕过
    Python实现EasyOCR对图片的自动识别,并提取目标数据
    Vue、React和小程序中的组件通信:父传子和子传父
    VNC图形化远程连接Ubuntu服务器
    python+pytest接口自动化之参数关联
    MyBatis-Plus详解
    轻松了解JVM
    base64_encode()和base64_decode(),URL的加密解密详解
    Encoder——Decoder工作原理与代码支撑
  • 原文地址:https://blog.csdn.net/Xin_101/article/details/127940801