SpringCloud工作筆記038---spring cloud-簡單閘道器許可權控制_直接在zuul裡面做
這樣也是一種方式吧,比較Low的一種吧,應該是,
在閘道器裡,判斷,是否有token,當然不能攔截登入啊,登入的時候本來就沒有token,
登入以後,判斷如果有token,就轉發,轉發以後就到了,對應的微服務中的controller中了,這樣
在controller,做具體的許可權控制,一般都是對url做的許可權吧,不過我們這個太噁心嘛?
你們都沒有這種需求嗎,就是不同的角色,訪問同一個url,會返回不同的資料,還是說,
這是兩種設計思想,就是,對於不同的角色,就應該對應不同的url,通過不同的url來返回不同的資料
------------------------------------------------------------------------------------------------------------
看下面的做法吧:
閘道器api Gateway的重要性不言而喻,閘道器負責統一接收所有請求,然後根據不同的規則進行轉發到不同的服務。使用閘道器能夠統一的管理請求日誌、進行許可權控制、過濾等,這樣就能避免在每個單體應用中做重複的工作。
這一篇主要是講zuul的獨立使用,就是隻作為一個獨立的專案進行請求轉發,而不關聯SpringCloud的那一堆Eureka、Ribbon等,因為很多時候我們的專案並不都是基於springcloud的微服務,或者不想搞那麼麻煩用註冊中心什麼的,就只想做個簡單的請求轉發代理和許可權控制。
zuul是可以進行開發的,裡面可以自定義一些自己的規則,譬如涉及查表之類的,能夠完成顆粒很細的需求。
這裡我們打算完成如下的功能,當訪問ip/user時就進入到User的獨立專案中,訪問ip/club時就進入到club的獨立專案中。入口是zuul,在zuul裡做許可權控制,譬如查表過濾黑名單、限制同一個userId單位時間內的訪問次數等。
請求轉發
使用zuul很簡單,新建一個Springboot專案,建立時勾選zuul即可。pom.xml如下
-
<?xml version="1.0" encoding="UTF-8"?>
-
<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.tianyalei</groupId>
-
<artifactId>testzuul</artifactId>
-
<version>0.0.1-SNAPSHOT</version>
-
<packaging>jar</packaging>
-
<name>testzuul</name>
-
<description>Demo project for Spring Boot</description>
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>1.5.6.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>Dalston.SR3</spring-cloud.version>
-
</properties>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-zuul</artifactId>
-
</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>
-
</plugins>
-
</build>
-
</project>
然後在Application類加上@EnableZuulProxy註解即可,該專案就具備了zuul的功能了
-
@EnableZuulProxy
-
@SpringBootApplication
-
public class TestzuulApplication {
-
public static void main(String[] args) {
-
SpringApplication.run(TestzuulApplication.class, args);
-
}
-
}
然後關鍵的地方在application.yml配置裡,規則在這裡配置
-
server:
-
port: 9000
-
zuul:
-
routes:
-
api-1:
-
path: /user/**
-
url: http://localhost:8081/
-
api-2:
-
path: /club/**
-
url: http://localhost:8082/
主要就是配置zuul.routes相關,api-1名字隨便起,主要是配置裡面的path和url這個是固定的
通過原始碼可以看到支援serviceId,url兩種,path是固定的,代表訪問zuul時的路徑,url代表訪問該路徑時會被轉發到哪個url上,serviceId是給springcloud用的,代表在Eureka上註冊的服務id,也是確定是轉發到哪一個服務的。
這裡我們配置的是url,當訪問localhost:9000/user/abc時,就相當於訪問localhost:8081/abc.
到這裡就已經完成了請求轉發了,如果你本地跑了兩個專案,埠分別是8081,8082,就已經可以通過請求zuul配置的url規則訪問到了。
-
@RequestMapping("club")
-
public String index() {
-
return "hello,我來自Club客戶端";
-
}
許可權控制
在zuul裡新建一個AccessFilter類,如下的寫法。
-
package com.tianyalei.testzuul;
-
import com.netflix.zuul.ZuulFilter;
-
import com.netflix.zuul.context.RequestContext;
-
import org.slf4j.Logger;
-
import org.slf4j.LoggerFactory;
-
import org.springframework.stereotype.Component;
-
import javax.servlet.http.HttpServletRequest;
-
@Component
-
public class AccessFilter extends ZuulFilter {
-
private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
-
@Override
-
public String filterType() {
-
//前置過濾器
-
return "pre";
-
}
-
@Override
-
public int filterOrder() {
-
//優先順序,數字越大,優先順序越低
-
return 0;
-
}
-
@Override
-
public boolean shouldFilter() {
-
//是否執行該過濾器,true代表需要過濾
-
return true;
-
}
-
@Override
-
public Object run() {
-
RequestContext ctx = RequestContext.getCurrentContext();
-
HttpServletRequest request = ctx.getRequest();
-
log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString());
-
//獲取傳來的引數accessToken
-
Object accessToken = request.getParameter("accessToken");
-
if(accessToken == null) {
-
log.warn("access token is empty");
-
//過濾該請求,不往下級服務去轉發請求,到此結束
-
ctx.setSendZuulResponse(false);
-
ctx.setResponseStatusCode(401);
-
ctx.setResponseBody("{\"result\":\"accessToken is empty!\"}");
-
return null;
-
}
-
//如果有token,則進行路由轉發
-
log.info("access token ok");
-
//這裡return的值沒有意義,zuul框架沒有使用該返回值
-
return null;
-
}
-
}
別的先不管,看看run方法,在這裡可以獲取到使用者傳來的所有引數,然後可以配置自己的規則來決定是否往最終的服務轉發請求,false為不給最終的服務傳送這次請求,預設為true。在這裡,我們設定如果accessToken為空,就停止轉發,直接給客戶端返回結果。需要注意一點,Filter是可以配置多個的,按照order從小到大依次執行,即使設定了setSendZuulResponse(false),也是會繼續執行下一個Filter的。
注意,路由轉發的停止和繼續是由ctx.setSendZuulResponse來控制的,與下面的return null無關,這個方法的return值沒有意義,並沒有使用。
效果如圖
下一篇來詳細看看Filter的配置。