一、網關Zuul
SpringCloud的Zuul組件,爲我們提供了路由轉發的功能,同時在路由過程中,還可以進行日誌打印,權限控制等功能。日誌打印以及權限控制可以通過實現ZuulFilter來進行:
package com.zhou.config;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class MyFilter extends ZuulFilter {
/**
* 返回一個字符串代表過濾器的類型,在zuul中定義了四種不同生命週期的過濾器類型,具體如下:
* pre 路由之前
* routing 路由之時
* post 路由之後
* error 發生錯誤時
* 常亮可以查看 FilterConstants
*/
@Override
public String filterType() {
return "pre";
}
/**
* 過濾器的過濾順序
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 這裏可以寫邏輯判斷,是否要過濾,true,永遠過濾。
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 過濾器的具體邏輯。可用很複雜,包括查sql,nosql去判斷該請求到底有沒有權限訪問。
*/
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
System.out.println(request.getRequestURI());
System.out.println(request.getRequestURL());
Object accessToken = request.getParameter("token");
if(accessToken == null) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
}catch (Exception e){}
return null;
}
return null;
}
}
上面的代碼中,就進行了一個最簡單的權限校驗功能(實際的權限控制比這個複雜的多,下面會詳細講解)。通過Filter,還可以在網關層進行日誌打印的功能,但是在日誌打印時,需要注意我們進行打印請求頭與響應體時,需要從Request和Response中獲取IO流來進行打印,而普通IO是無法進行復用的,因此,需要注意在打印日誌時,需要將文件下載上傳類的接口過濾,以避免文件內容爲空的問題。
二、網關層服務鑑權方案
網關層服務鑑權方案屬於一種比較常見的服務鑑權方案,在權限需要靈活配置的情況下用此方案比較好,該方案的優勢在於不與業務代碼耦合,是否開放接口,可以通過後臺進行設置,而不需要去變更代碼。
權限綁定關係:url -> 前端Model -> 權限包集合 -> 用戶角色
下方流程圖即爲鑑權流程:
在上圖中,任何用戶訪問後臺需要經過以下步驟:
1.請求被網關層攔截
2.網關層請求鑑權服務進行鑑權,查看是否具有權限,不具備權限則將其攔截
3.網關層轉發至服務層
同時,權限的url變更,只需要由後臺人員對鑑權服務中的數據進行變更即可,不需要變更後端的服務代碼,同時,後端的服務業務開發人員也不需要關注權限url的變更。
三、Controller層AOP鑑權
Controller層AOP鑑權與網關層鑑權有所不同,其權限綁定結構相比網關層鑑權,減少了一層url層的數據。
權限綁定關係:前端Model -> 權限包集合 -> 用戶角色
同時,該方式鑑權優勢也具有劣勢。
1.劣勢
要求被權限保護的接口不能被微服務內部訪問,否則會造成重複鑑權。
會導致權限與AOP的註解代碼綁死,如果希望取消某個接口的權限,或者新增某個接口的權限,就需要對AOP的註解代碼進行變更。
2.優勢
可以將參數納入權限控制。例如:用戶A只具有“杭州”的數據的訪問權限,那麼就需要將請求參數納入到鑑權的範圍中,但是接口的參數模型是不一樣的,此時利用AOP註解就可以進行輕鬆的鑑權配置,而網關層不行。
可以減少配置的權限數量,並且去掉url層的權限數據,直接在AOP註解上配置前端Model層的權限信息。
四、總結
目前,在我周圍使用SpringCloud的公司中,分採用網關層鑑權的方案進行鑑權的較多,但是兩種方案本身是各有優劣的,並沒有實際的孰好孰壞。
其實本質上,權限的校驗方案本身都比較通用化,但是因爲權限本身,需要對大量的接口進行攔截處理,並且,每次鑑定權限在無緩存支撐的情況下,會每一次查詢多張數據庫表,吃掉大量的服務器性能。因此,在進行鑑權系統的開發時,無論採用哪一種方案,做好適當的多級緩存,纔是重中之重。