SpringClond微服务架构篇 三 、网关gateway篇

网管概述:

Spring Cloud Gateway 是 Spring Cloud 家族中的新一代微服务网关框架,它为构建 API 网关提供了强大的功能。Spring Cloud Gateway 的核心组件之一就是过滤器,本文将详细介绍 GlobalFilterGatewayFilter 和 AbstractGatewayFilterFactory 三种过滤器的实现方式,并探讨如何在实践中高效地使用它们。

文章汇总:

Spring Cloud Gateway网关是通用微服务。本文档适用于使用效率的文章,在底层及文化概念层面未深入研究。

maven引入

   <dependencies>

        <!-- swagger聚合-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-gateway-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>

        <!--  请求调用-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.netflix.archaius</groupId>
                    <artifactId>archaius-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.pinyi.supply</groupId>
            <artifactId>system-api</artifactId>
        </dependency>
        <!--nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2021.0.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
        </dependency>
        <!--gateway依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

全局拦截器

介绍:本拦截器逻辑不多。其中两个方法

permissionService.ignoreAuthentication(requestPath); // 验证是否白名单
permissionService.invalidAccessToken(token);//验证是否token有效

其中包含了传递用户信息头操作

经过这两层即可放行

/**
 * 全局过滤器
 */
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {


    @Autowired
    WhiteConfig whiteConfig;

    @Resource
    PermissionService permissionService;


    // Getter or any other methods you need
    public List<String> whiteList() {
        return whiteConfig.getList();
    }

    /**
     * 是否包含url
     *
     * @param url 地址
     * @return 布尔值
     */
    private boolean contains(String url) {
        for (String s : Constants.AUTH_EXCLUDE_URLS) {
            if (url.contains(s)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 响应信息
     */
    private Mono<Void> writer(HttpStatus code, ServerHttpResponse response, String msg) {
        response.setStatusCode(code);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response
                .writeWith(Flux.just(response
                        .bufferFactory()
                        .wrap(JSON.toJSONBytes(HttpResult.error(code, msg)))));
    }


    //@Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 请求路径
        String requestPath = String.valueOf(exchange.getRequest().getPath());
        log.info("网关路由路径:{}", requestPath);
        // 打印访问情况
        log.info("访问情况:{} {} {} {}", request.getRemoteAddress(), request.getMethod(), response.getStatusCode(), request.getPath());
        MultiValueMap<String, String> requestQueryParams = request.getQueryParams();
        log.info("请求参数:{}", requestQueryParams);


        HttpResult result;
        try {
            result = permissionService.ignoreAuthentication(requestPath);
            // 判断是否是白名单
            if (result.getData().equals(true)) {
                // 创建新的请求对象,并添加放行标识
                ServerHttpRequest mutatedRequest = exchange.getRequest()
                        .mutate()
                        .header("Release-Flag", String.valueOf(result.getData()))  // 添加自定义头部放行标识
                        .build();

                // 使用新的请求对象创建新的 ServerWebExchange
                ServerWebExchange mutatedExchange = exchange.mutate()
                        .request(mutatedRequest)
                        .build();
                return chain.filter(mutatedExchange);
            }

            //验证是否存在权限
            String token = request.getHeaders().getFirst("Authorization");
            if (StringUtils.isBlank(token)) {
                return writer(HttpStatus.UNAUTHORIZED, response, "暂未登录,请先登录");
            }
            //验证token
            HttpResult invalided = permissionService.invalidAccessToken(token);
            JSONObject data = JSON.parseObject(JSON.toJSONString(invalided.getData()), JSONObject.class);
            if (invalided.getCode() != HttpStatus.OK.value()) {
                return writer(HttpStatus.UNAUTHORIZED, response, invalided.getMsg());
            } else {
                if (!data.getBoolean("tokenStatus").equals(true)) {
                    return writer(HttpStatus.UNAUTHORIZED, response, invalided.getMsg());
                }
            }


            // 创建新的请求对象,并添加放行标识
            ServerHttpRequest mutatedRequest = exchange.getRequest()
                    .mutate()
                    .header("Release-Flag",  String.valueOf(result.getData()))
                    .header("Login-user", data.getString("userName"))  // 添加自定义头部放行标识
                    .build();

            // 使用新的请求对象创建新的 ServerWebExchange
            ServerWebExchange mutatedExchange = exchange.mutate()
                    .request(mutatedRequest)
                    .build();
            return chain.filter(mutatedExchange);
        } catch (Exception e) {
            return writer(HttpStatus.UNAUTHORIZED, response, e.getMessage());
        }


    }

    @Override
    public int getOrder() {
        return -2;
    }

}

接口实现service

/**
 * 统一鉴权service
 * @author zhangzhiwei
 */
public interface PermissionService {





//
//    /**
//     * 调用签权服务,判断用户是否有权限
//     *
//     * @param authentication 权限标识
//     * @param url 请求url
//     * @param method 请求方法
//     * @return true/false
//     */
//    boolean hasPermission(String authentication, String url, String method);

    /**
     * 获取正确的token
     *
     * @param authentication 权限标识
     */
    HttpResult invalidAccessToken(String authentication) throws AuthenticationException;

    /**
     * 判断url是否不需要授权
     * @param url 请求url
     * @return true为不需要授权
     */
    HttpResult ignoreAuthentication(String url) throws AuthenticationException;
}

impl层

    /**
     * 判断token是否有效
     *
     * @param authentication 权限标识
     * @return ture 有效 false 无效
     */

    @Override
    public HttpResult invalidAccessToken(String authentication) throws AuthenticationException {
        HttpResult httpResult = authService.invalidAccessToken(authentication);
        return httpResult;

    }

    /**
     * 判读那是否是白名单
     *
     * @param url 请求url
     * @return true是 false不是
     */

    @Override
    public HttpResult ignoreAuthentication(String url) throws AuthenticationException {
        return authService.isWhiteOpen(url);
    }

使用feign进行远程调用

/**
 * 鉴权接口
 *
 * @author zhangzhiwei
 */
@FeignClient(contextId = "authService", value = "security", fallbackFactory = RemoteAuthServiceFactory.class)
public interface RemoteAuthService {


    /**
     * 判断是否是白名单
     *
     * @param url 请求url
     * @return true/false
     */
    @GetMapping("/permission/isWhiteOpen")
    public HttpResult isWhiteOpen(@RequestParam(value = "url") String url);

    /**
     * 验证token是否有效
     *
     * @param authentication token
     * @return true/false
     */
    @GetMapping("/permission/isValid")
        public HttpResult invalidAccessToken(@RequestParam(value = "authentication") String authentication);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值