互聯網API開放平臺安全設計(五)---APIGateway網關

什麼是網關

隨着互聯網的快速發展,當前以步入移動互聯、物聯網時代。用戶訪問系統入口也變得多種方式,由原來單一的PC客戶端,變化到PC客戶端、各種瀏覽器、手機移動端及智能終端等。同時系統之間大部分都不是單獨運行,經常會涉及與其他系統對接、共享數據的需求。所以系統需要升級框架滿足日新月異需求變化,支持業務發展,並將框架升級爲微服務架構。“API網關”核心組件是架構用於滿足此些需求。

很多互聯網平臺已基於網關的設計思路,構建自身平臺的API網關,國內主要有京東、攜程、唯品會等,國外主要有Netflix、Amazon等。

網關框架框架

業界爲了滿足這些需求,已有相關的網關框架。

1、基於nginx平臺實現的網關有:KONG、API Umbrella

2、自研發的網關有:apigee、Zuul

API網關設計

API網關是微服務架構(Microservices Architecture)標準化服務的模式。API網關定位爲應用系統服務接口的網關,區別於網絡技術的網關,但是原理則是一樣。API網關統一服務入口,可方便實現對平臺衆多服務接口進行管控,對訪問服務的身份認證、防報文重放與防數據篡改、功能調用的業務鑑權、響應數據的脫敏、流量與併發控制,甚至基於API調用的計量或者計費等等。組件設計如下:

網關的應用場景

  1. 黑白名單:實現通過IP地址控制禁止訪問網關功能,此功能是應用層面控制實現,再往前也可以通過網絡傳輸方面進行控制訪問。
  2. 日誌:實現訪問日誌的記錄,可用於分析訪問、處理性能指標,同時將分析結果支持其他模塊功能應用。
  3. 協議適配:實現通信協議校驗、適配轉換的功能。
  4.  身份認證:負責網關訪問身份認證驗證,此模塊與“訪問認證中心”通信,實際認證業務邏輯交移“訪問認證中心”處理。
  5. 計流限流:實現微服務訪問流量計算,基於流量計算分析進行限流,可以定義多種限流規則。
  6. 路由:路由是API網關很核心的模塊功能,此模塊實現根據請求,鎖定目標微服務並將請求進行轉發。此模塊需要與“服務發佈管理中心”通信。“服務發佈管理中心”實現微服務發佈註冊管理功能,與其通信獲得目標微服務信息。

API網關部署

API網關是一個公共基礎組件,無狀態,可支持多套分佈式部署。如下圖所示:

基於Nginx實現API網關

Nginx配置

http {

    include       mime.types;

    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {

        listen       80;

        server_name  localhost;

        location /api-a {

            proxy_pass   http://127.0.0.1:8000/;

            index  index.html index.htm;

        }

                   location /api-b {

            proxy_pass   http://127.0.0.1:8001/;

            index  index.html index.htm;

        }

    }

}

 

基於Zuul實現API網關

搭建註冊中心

創建項目eureka_server

eureka_server pom依賴信息

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

      <modelVersion>4.0.0</modelVersion>

      <groupId>com.itmayiedu</groupId>

      <artifactId>eureka_server</artifactId>

      <version>0.0.1-SNAPSHOT</version>

      <parent>

           <groupId>org.springframework.boot</groupId>

           <artifactId>spring-boot-starter-parent</artifactId>

           <version>2.0.1.RELEASE</version>

      </parent>

 

      <!-- 管理依賴 -->

      <dependencyManagement>

           <dependencies>

                 <dependency>

                      <groupId>org.springframework.cloud</groupId>

                      <artifactId>spring-cloud-dependencies</artifactId>

                      <version>Finchley.M7</version>

                      <type>pom</type>

                      <scope>import</scope>

                 </dependency>

           </dependencies>

      </dependencyManagement>

      <dependencies>

 

           <dependency>

                 <groupId>org.springframework.cloud</groupId>

                 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>

           </dependency>

 

 

      </dependencies>

 

      <!-- 注意: 這裏必須要添加, 否者各種依賴有問題 -->

      <repositories>

           <repository>

                 <id>spring-milestones</id>

                 <name>Spring Milestones</name>

                 <url>https://repo.spring.io/libs-milestone</url>

                 <snapshots>

                      <enabled>false</enabled>

                 </snapshots>

           </repository>

      </repositories>

 

      <build>

           <plugins>

                 <plugin>

                      <groupId>org.springframework.boot</groupId>

                      <artifactId>spring-boot-maven-plugin</artifactId>

                 </plugin>

           </plugins>

      </build>

</project>

 application.yml  配置信息

server:

  port: 8100

eureka:

  instance:

    hostname: server1

  client:

    serviceUrl:

          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

    register-with-eureka: false

    fetch-registry: false

server:

  port: 8100

eureka:

  instance:

    hostname: server1

  client:

    serviceUrl:

          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

    register-with-eureka: false

    fetch-registry: false

 啓動類

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
	public static void main(final String[] args) {
		SpringApplication.run(EurekaApplication.class, args);
	}
}

 創建A服務項目

@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class AIndexController {
	@RequestMapping("/")
	public String index() {
		return "我是A項目....";
	}

	public static void main(String[] args) {
		SpringApplication.run(AIndexController.class, args);
	}
}

 

server:

  port: 8000

spring:

    application:

        name: itmayiedu_a

eureka:

  client:

    service-url:

           defaultZone: http://localhost:8100/eureka

創建B服務項目

@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class AIndexController {
	@RequestMapping("/")
	public String index() {
		return "我是B項目....";
	}

	public static void main(String[] args) {
		SpringApplication.run(AIndexController.class, args);
	}
}

 

server:

  port: 8000

spring:

    application:

        name: itmayiedu_a

eureka:

  client:

    service-url:

           defaultZone: http://localhost:8100/eureka

創建 zuul-gateway 項目

創建 zuul-gateway Pom依賴

 

      <parent>

           <groupId>org.springframework.boot</groupId>

           <artifactId>spring-boot-starter-parent</artifactId>

           <version>2.0.1.RELEASE</version>

           <relativePath /> <!-- lookup parent from repository -->

      </parent>

 

      <properties>

           <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

           <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

           <java.version>1.8</java.version>

           <spring-cloud.version>Finchley.RC1</spring-cloud.version>

      </properties>

      <dependencies>

           <dependency>

                 <groupId>org.springframework.boot</groupId>

                 <artifactId>spring-boot-starter</artifactId>

           </dependency>

           <dependency>

                 <groupId>org.springframework.cloud</groupId>

                 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

           </dependency>

           <dependency>

                 <groupId>org.springframework.cloud</groupId>

                 <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>

           </dependency>

           <dependency>

                 <groupId>org.springframework.cloud</groupId>

                 <artifactId>spring-cloud-starter-netflix-zuul</artifactId>

           </dependency>

           <dependency>

                 <groupId>org.projectlombok</groupId>

                 <artifactId>lombok</artifactId>

                 <optional>true</optional>

           </dependency>

           <dependency>

                 <groupId>com.alibaba</groupId>

                 <artifactId>fastjson</artifactId>

                 <version>1.2.3</version>

           </dependency>

           <dependency>

                 <groupId>org.springframework.boot</groupId>

                 <artifactId>spring-boot-starter-test</artifactId>

                 <scope>test</scope>

           </dependency>

      </dependencies>

 

      <dependencyManagement>

           <dependencies>

                 <dependency>

                      <groupId>org.springframework.cloud</groupId>

                      <artifactId>spring-cloud-dependencies</artifactId>

                      <version>${spring-cloud.version}</version>

                      <type>pom</type>

                      <scope>import</scope>

                 </dependency>

           </dependencies>

      </dependencyManagement>

 

      <build>

           <plugins>

                 <plugin>

                      <groupId>org.springframework.boot</groupId>

                      <artifactId>spring-boot-maven-plugin</artifactId>

                 </plugin>

                 <plugin>

                      <groupId>org.apache.maven.plugins</groupId>

                      <artifactId>maven-compiler-plugin</artifactId>

                      <configuration>

                            <source>1.8</source>

                            <target>1.8</target>

                      </configuration>

                 </plugin>

                 <plugin>

                      <groupId>org.apache.maven.plugins</groupId>

                      <artifactId>maven-resources-plugin</artifactId>

                      <version>3.0.1</version>

                      <executions>

                            <execution>

                                  <id>copy-conf</id>

                                  <phase>package</phase>

                                  <goals>

                                       <goal>copy-resources</goal>

                                  </goals>

                                  <configuration>

                                       <encoding>UTF-8</encoding>

                                        <outputDirectory>${project.build.directory}/ext/conf</outputDirectory>

                                       <resources>

                                             <resource>

                                                  <directory>ext/conf</directory>

                                                  <includes>

                                                        <include>logback.xml</include>

                                                  </includes>

                                                  <filtering>true</filtering>

                                             </resource>

                                       </resources>

                                  </configuration>

                            </execution>

                      </executions>

                 </plugin>

                 <plugin>

                      <groupId>org.jacoco</groupId>

                      <artifactId>jacoco-maven-plugin</artifactId>

                      <version>0.7.5.201505241946</version>

                      <executions>

                            <execution>

                                  <id>default-prepare-agent</id>

                                  <goals>

                                       <goal>prepare-agent</goal>

                                  </goals>

                            </execution>

                            <execution>

                                  <id>default-prepare-agent-integration</id>

                                  <goals>

                                       <goal>prepare-agent-integration</goal>

                                  </goals>

                            </execution>

                      </executions>

                 </plugin>

                 <plugin>

                      <groupId>com.spotify</groupId>

                      <artifactId>docker-maven-plugin</artifactId>

                      <version>0.4.3</version>

                      <configuration>

                            <imageName>hy_uav_gateway</imageName>

                            <dockerDirectory>src/main/docker</dockerDirectory>

                            <resources>

                                  <resource>

                                       <targetPath>/</targetPath>

                                       <directory>${project.build.directory}</directory>

                                       <include>${project.build.finalName}.jar</include>

                                       <include>ext/conf/logback.xml</include>

                                  </resource>

                            </resources>

                      </configuration>

                 </plugin>

           </plugins>

      </build>

 

      <repositories>

           <repository>

                 <id>spring-milestones</id>

                 <name>Spring Milestones</name>

                 <url>https://repo.spring.io/milestone</url>

                 <snapshots>

                      <enabled>false</enabled>

                 </snapshots>

           </repository>

      </repositories>

 配置application 依賴信息

eureka:

  client:

    serviceUrl:

      defaultZone: http://localhost:8100/eureka/

server:

  port: 8769

spring:

  application:

    name: service-zuul

zuul:

  routes:

    api-a:

      path: /api-a/**

      serviceId: itmayiedu_a

    api-b:

      path: /api-b/**

      serviceId: itmayiedu_b

ZuulApplication啓動運行

@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class ZuulApplication {

	public static void main(String[] args) {
		SpringApplication.run(ZuulApplication.class, args);
	}

	@Bean
	public TokenFilter accessFilter() {
		return new TokenFilter();
	}
}

過濾器攔截參數

// 使用網關攔截Token參數
public class TokenFilter extends ZuulFilter {

	public Object run() throws ZuulException {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		Object accessToken = request.getParameter("accessToken");
		if (accessToken == null) {
			// 返回錯誤信息
			ctx.setSendZuulResponse(false);
			ctx.setResponseStatusCode(401);
			ctx.setResponseBody("accessToken is null");
			return null;
		}
		return null;
	}

	public boolean shouldFilter() {
		return true;// 是否執行該過濾器,此處爲true,說明需要過濾
	}

	@Override
	public int filterOrder() {
		return 0;// 優先級爲0,數字越大,優先級越低
	}

	@Override
	public String filterType() {
		return "pre"; // 前置過濾器
	}

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章