• 这里我们着重关注在应用层拦截这种解决方案。

    实现思路

    实现思路其实也很简单,在请求经过网关的时候给请求头中增加一个额外的Header,在后端服务中写一个拦截器,判断请求头是否与在网关设置的请求Header一致,如果不一致则不允许访问并给出提示。

    当然为了防止在每个后端服务都需要编写这个拦截器,我们可以将其写在一个公共的starter中,让后端服务引用即可。而且为了灵活,可以通过配置决定是否只允许后端服务访问。

    接下来我们看看核心代码。(代码中涉及 SpringBoot 编写公共Starter的套路,相信看过我博客的同学肯定是会的,因为之前文章有详细说过。)

    实现过程

    @Component
    @Order(0)
    public class GatewayRequestFilter implements GlobalFilter {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            byte[] token = Base64Utils.encode((CloudConstant.GATEWAY_TOKEN_VALUE).getBytes());
            String[] headerValues = {new String(token)};
            ServerHttpRequest build = exchange.getRequest()
                    .mutate()
                    .header(CloudConstant.GATEWAY_TOKEN_HEADER, headerValues)
                    .build();

            ServerWebExchange newExchange = exchange.mutate().request(build).build();
            return chain.filter(newExchange);
        }

    }

    在请求经过网关时添加额外的Header,为了方便这里直接设置成固定值。


    @Data
    @ConfigurationProperties(prefix = "javadaily.cloud")
    public class CloudSecurityProperties {

        /**
         * 是否只能通过网关获取资源
         * 默认为True
         */

        private Boolean onlyFetchByGateway = Boolean.TRUE;

    }


    public class ServerProtectInterceptor implements HandlerInterceptor {

        private CloudSecurityProperties properties;

        @Override
        public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler){

            if (!properties.getOnlyFetchByGateway()) {
                return true;
            }

            String token = request.getHeader(CloudConstant.GATEWAY_TOKEN_HEADER);

            String gatewayToken = new String(Base64Utils.encode(CloudConstant.GATEWAY_TOKEN_VALUE.getBytes()));

            if (StringUtils.equals(gatewayToken, token)) {
                return true;
            } else {
                ResultData<String> resultData = new ResultData<>();
                resultData.setSuccess(false);
                resultData.setStatus(HttpServletResponse.SC_FORBIDDEN);
                resultData.setMessage("请通过网关访问资源");
                WebUtils.writeJson(response,resultData);
                return false;
            }
        }

        public void setProperties(CloudSecurityProperties properties) {
            this.properties = properties;
        }
    }


    public class CloudSecurityInterceptorConfigure implements WebMvcConfigurer {

        private CloudSecurityProperties properties;

        @Autowired
        public void setProperties(CloudSecurityProperties properties) {
            this.properties = properties;
        }

        @Bean
        public HandlerInterceptor serverProtectInterceptor() {
            ServerProtectInterceptor interceptor = new ServerProtectInterceptor();
            interceptor.setProperties(properties);
            return interceptor;
        }

        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(serverProtectInterceptor());
        }
    }


    @EnableConfigurationProperties(CloudSecurityProperties.class)
    public class CloudSecurityAutoConfigure
    {

        @Bean
        public CloudSecurityInterceptorConfigure cloudSecurityInterceptorConfigure() {
            return new CloudSecurityInterceptorConfigure();
        }

    }


    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
       com.javadaily.component.security.configure.CloudSecurityAutoConfigure


    javadaily:
      cloud:
        onlyFetchByGateway: true

    经过以上几步,一个公共的Starter模块就构建完成了。

    <dependency>
     <groupId>com.jianzh5.cloud</groupId>
     <artifactId>cloud-component-security-starter</artifactId>
    </dependency>

    实现效果

    直接访问后端服务接口  
    http://localhost:8010/account/getByCode/jianzh5

    SpringCloud Alibaba微服务实战二十七 - 禁止直接访问后端服务-LMLPHP

    返回结果:

    {
      "message""请通过网关访问资源",
      "status"403,
      "success"false,
      "timestamp"1611660015830
    }


    以上,希望对你有所帮助!



    SpringCloud Alibaba微服务实战二十七 - 禁止直接访问后端服务-LMLPHP





    本文分享自微信公众号 - JAVA日知录(javadaily)。
    如有侵权,请联系 support@oschina.cn 删除。
    本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

    03-07 16:50