巧用网关白名单实现接口免鉴权

2023年 7月 31日 18.3k 0

分享技术,用心生活

场景描述:一般系统中提供的接口都是经过统一配置鉴权的,比如不登录不能访问。但是,一些接口是需要开放给客户用的,我称作open API。那么这时候你不能要求客户先登录你的接口再去调用吧。那么,这时候就可以通过网关白名单来实现免鉴权

先说思路:

  • 配置网关白名单列表
  • 编写鉴权过滤器
  • 过滤器中读取白名单
  • 业务处理
  • 简单的时序图

    sequenceDiagram
    用户->>过滤器: 发起请求
    过滤器->>过滤器: 校验白名单
    过滤器->>业务系统: 通过
    过滤器-->>用户: 不通过
    业务系统--)用户: success
    

    注: 如果使用的是网关过滤器,在校验后应该再次过滤器,也就是经过2次;注意区别(网关过滤器具有前置pre、后置post两次过滤,细节不在此处详细探讨)。

    过滤器普遍用于处理拦截,校验,改写,日志等场景;通过白名单来控制鉴权,正契合过滤器的作用。

    1. 配置网关白名单

    在你的本地的配置文件或者是nacos的配置文件中新增以下配置

    可以配置url全路径,也可以配置前缀路径

    gateway:
      whitelist:
        - /user/api/userInfo/query
        - /open/oss/upload
        - /open/vod/api
    

    2. 过滤器配置

    过滤器你可以选择用spring的WebFilter,如果你的系统集成了gateway也可以使用网关过滤器,然后自定义过滤器实现GlobalFilter

    2.1. WebFilter实现

    @Component
    @RequiredArgsConstructor
    public class AuthFilter implements WebFilter, Ordered {
    
        private final GateWayProperties gateWayProperties;
    
        private static final AntPathMatcher pathMatcher = new AntPathMatcher();
    
        @Override
        public int getOrder() {
            return 1;
        }
    
        @Override
        protected Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
            ServerHttpRequest request = exchange.getRequest();
            String urlMethod = request.getURI().getPath();
    
            // 白名单匹配,直接放行
            for (String pattern : gateWayProperties.getWhitelist()) {
                if (pathMatcher.matchStart(pattern, urlMethod)) {
                    return chain.filter(exchange);
                }
            }
           // 未匹配到
           // 鉴权逻辑,此处省略....
        }
    
    }
    

    2.2. 网关GlobalFilter实现

    @Component
    @RequiredArgsConstructor
    public class AuthFilter implements GlobalFilter, Ordered {
    
        private final GateWayProperties gateWayProperties;
    
        private static final AntPathMatcher pathMatcher = new AntPathMatcher();
    
    
        @Override
        public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpRequest request = exchange.getRequest();
            String urlMethod = request.getURI().getPath();
    
            // 白名单匹配,直接放行
            for (String pattern : gateWayProperties.getWhitelist()) {
                if (pathMatcher.matchStart(pattern, urlMethod)) {
                    return chain.filter(exchange);
                }
            }
            // 未匹配到,忽略鉴权逻辑,直接设置401
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }
    

    2.3. 读取白名单配置

    GateWayProperties中的prefix要和配置文件中的名称保持一致

    @Getter
    @Setter
    @ToString
    @ConfigurationProperties(prefix = "gateway")
    public class GateWayProperties implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        private List whitelist;
    
    }
    

    3. 演示效果

    使用上面配置的查询用户信息接口/user/api/userInfo/query做演示

    3.1. 在白名单内

    • WebFilter效果

    查看断点gateWayProperties中白名单列表已获取到,且比对结果为true

    WebFilter

    • GlobalFilter效果

    查看断点gateWayProperties中白名单列表也已获取到,且比对结果为true

    GlobalFilter

    查询结果:已获取到用户信息

    结果

    3.2. 不在白名单内

    我们把接口/user/api/userInfo/query从白名单中删除,用网关过滤器演示。

    查看断点gateWayProperties中白名单列表已没有查询用户接口,且返回了401

    GlobalFilter

    查询结果:http状态码是我们设置的401

    结果

    当然,使用白名单也不仅仅局限于对外开放接口这个场景,也不仅仅局限于使用在鉴权过滤器上。这里只是一个抛砖引玉。实际需求可以结合自己的业务场景,使用不同的过滤器。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论