路由:她會把外部所有對請求轉發到具體的微服務實例上,是實現外部訪問同一接口的基礎
過濾: 就是權限的檢查, 判斷當前的請求是否有權限區訪問那些服務集群
搭建后台網關:
-
導入eureka - client, 它本身也是一個客戶端,需要注冊進eureka
- 導入網關的包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
過濾器, 重寫下面的ZuulFilter可以實現自定義的過濾規則, 每個方法的含義都通過注釋的方式寫在了方法頭
網關的過濾器
@Component
public class WebManagerFilter extends ZuulFilter {
/**
* 指定過濾器的類型
pre :可以在請求被路由之前調用
route :在路由請求時候被調用
post :在route和error過濾器之后被調用
error :處理請求時發生錯誤時被調用
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 指定過濾器的優先級, 0表示優先執行, 因為我們可以寫很多個過濾器
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 當前過濾器是否開啟, true表示開啟
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 過濾器執行邏輯, 返回任意Object類型的值,都表示放行,包括null
* 如果不想往后繼續執行了,就使用 setSendZullResponse(false)
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("經過了后台的過濾器");
return null;
}
}
我們可以通過RequestContext的實例對象,獲取出請求頭,請求parms,請求ip等信息, 針對不同的信息可以做出不同的處理
黑白名單
比如我們可以在網關中禁用掉惡意訪問的ip地址
驗證權限
如果項目是前后端分離使用jwt等工具生成token放在請求頭中做安全驗證,我們也能在網關中對請求頭做出初步解析處理
防止抓包
還能根據用戶請求中發送過來的請求參數做驗證簽名處理, 防止數據在傳輸過程中被惡意篡改
此外,網關會過濾掉一些請求的請求頭,如果請求頭是我們自己定義的,就比如下面的Authrization, 經過網關后的請求的頭信息會丟失,進而導致下面的這段代碼失效, 獲取不出頭信息,就沒辦法驗證token的合法性
解決辦法: 選着添加添加一條配置信息 sensitive-headers:
將這個配置置空,意為清空網關要過濾的請求頭
RequestContext currentContext = RequestContext.getCurrentContext();
String header = currentContext .getRequest().getHeader("Authorization");
System.err.println("zull header "+header);
// 判斷是否存在header
if (!"".equals(header)&&header!=null){
System.err.println("轉發header");
currentContext.addZuulRequestHeader("Authorization",header);
}
使用過濾器做驗證的邏輯如下,驗證攜帶在請求頭中的token信息如下:
這個方法的特點就是, 只要他能在遇到 return null
就表示成功完成了驗證的邏輯
1. 導入 common,我們要使用它的jwtUtil
@Override
public Object run() throws ZuulException {
System.err.println("經過了后台的過濾器");
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
// 獲取出請求頭
String header = request.getHeader("Authorization");
// 放行zuul的第一次請求 todo 我並沒有觸發這個方法的執行
if (request.getMethod().equals("OPTIONS")){
System.err.println("OPTIONS");
return null;
}
// 放行登錄請求
if (request.getRequestURL().indexOf("login")>0){
return null;
}
if (StringUtils.isNotBlank(header)){
if (header.startsWith("Bearer ")){
String token = header.substring(7);
if (StringUtils.isNotBlank(token)){
System.out.println("token=="+token);
try{
Claims claims = jwtUtil.parseJWT(token);
String roles =(String) claims.get("roles");
System.out.println("roles=="+roles);
// 對admin放行,
if (roles.equals("admin")){
return null;
}
// todo 轉發頭信息,我改了配置文件, 讓zuul不過濾任何頭信息
// 其他情況, 終止訪問
currentContext.setSendZuulResponse(false);
}catch (Exception e){
// 解析token出現的異常,說明token有問題, 終止本次請求
System.out.println("token出錯了,終止本次訪問: "+e);
currentContext.setSendZuulResponse(false);
}
}
}
}
currentContext.setSendZuulResponse(false);
currentContext.getResponse().setContentType("text/html;chatset=utf-8");
try {
currentContext.getResponse().getWriter().write("權限不足");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}