一.目標
1.外部請求統一從網關zuul進入,而且服務內部互相調用接口要校驗權限html
2.cloud和shiro結合,達到單點登陸,和集中一個服務完成權限管理,其餘業務服務不須要關注權限如何實現mysql
3.其餘服務依然能夠控制權限細粒度到接口,如在接口上使用@RequirePermisson等註解,方便開發redis
二.思路
SpirngCloud zuul網關有兩個做用,一個是分配路由,一個是過濾。sql
zuul的過濾器做用有限,只能簡單的作一些某個url是否可以訪問之類的,沒法像shiro同樣細粒度到某個用戶是否有某種權限;數據庫
shiro單體應用你們都會作,那變成微服務後,難道每一個服務都要寫一套shiro框架?這顯然也太麻煩。後端
1.在zuul服務裏用shiro,作成動態url權限控制,就是把訪問哪一個url須要用什麼權限,寫入數據庫,在過濾器讀取與用戶有的權限做對比;可是服務互相調用校驗就行不通了,由於服務間調用不走zuul瀏覽器
2.寫一個服務專用於shiro認證和受權,包含用戶、權限的curd,暴露出查詢一個用戶擁有什麼權限的接口;在其餘服務中,都寫一個攔截器拿訪問者token去受權服務拿此用戶的權限,再跟請求的url對比;或者能夠自定義註解用aop,註解標註的是訪問此url須要什麼權限,遠程調用受權服務接口查詢當前用戶全部權限,與請求的url對比。緩存
可是這個要本身實現攔截器。安全
3.第二種思路的簡單版本。服務器
寫一個server服務專用於shiro認證和受權,包含用戶、權限的curd,暴露出查詢一個用戶擁有什麼權限的接口;
在寫一個client項目打成jar包供其餘服務使用,也是用shiro框架,不一樣於server服務的是,在realm中只有受權方法,沒有認證方法,而且受權方法的實現是去server遠程查詢權限,再返回給client項目的安全管理器。且client的登陸接口寫成server的登陸接口,這樣未登陸的用戶都會跳轉到server登陸,想辦法保存下原路徑,登陸成功後再返回原服務;同時作成session共享
普通業務服務只須要依賴於client,就至關於每一個服務都有了一套shiro。
這種思路來自於《跟我學shiro》的多項目集中權限,其實想一想這種思路是能夠的,shiro本質也是靠攔截器進行權限校驗,雖然至關於每一個服務都開啓了一套shiro,但也就是容器中多了一些shiro攔截器和實例,並且能夠用shiro的各類功能,開發方便。能夠完成咱們的三個目標。
三.其餘思路
1.分佈式session
用戶在網關進行登陸認證;若是經過,將用戶信息存在第三方組件,mysql、redis;後端其餘服務能夠經過第三方組件拿到用戶數據。
這種方案值得推薦,方便擴展,但依賴於第三方組件,注意第三方組件的高可用。
2.客戶端token與網關結合
服務器無session,將用戶信息存儲在token,好比JWT。
瞭解JWThttps://www.cnblogs.com/cjsblog/p/9277677.html
客戶端攜帶用jwt加密的token,訪問網關,token攜帶了用戶的信息
網關對token認證和校驗
校驗經過網關後,請求攜帶token到具體服務,能夠校驗具體的url權限
若是用戶信息量大,則不適合,由於都是存儲在客戶端的;而且token要在網關注註銷
zuul + OATHU2+JWT
3.瀏覽器cookie和網關結合。
和上述方案相同,區別是用戶信息徹底放在cookie,不用token
---------------------------------------------------------
外加一段優秀的對話:
A:大佬有沒有想過用單點登陸sso ,把登陸寫成一個服務shiro在這個服務裏面做用,須要訪問別的服務的時候zuul反向代理到sso的服務進行認證登陸,可這樣我如今遇到這樣的問題,shiro的受權怎麼才能被其餘的服務知道,而且在頁面進行細粒度級別標籤控制攔截
B 回覆 A: 嗯。不通過。zuul是給外部調用使用的。。
C回覆 A: 看文章,服務之間互相訪問是不通過zuul的,只有外部請求訪問才經過zull
B回覆 A: 其實有簡單的方法能夠實現相似的目標。就是把我的信息放在Redis或者其餘nosql庫裏,同時放入的還有我的的權限信息,包括可訪問的資源信息和角色。而後能夠用zuul來進行過濾判斷。這樣寫,就很簡單了。不須要用到shiro,也能夠避免不少問題。
B: 我如今的想法是吧feignServer單獨寫成服務,而後將接暴露,其餘服務調用這個接口,來進行判斷權限。可是這樣,會不會有網絡延遲發生?
B回覆 E: 我是返回統一的result的,裏面封裝了flag標識。。把shiro單獨寫成服務,有一個好處就是讓其餘服務不用再集成shiro,只要去訪問shiro這個服務就能知道是否有權限了。其餘服務若是要判斷的話,就去調用接口就行了。
B回覆 A: 可行。已經實現了。feignClient服務暴露出2個接口,權限和角色的認證接口就能夠了。注意feign的無狀態認證。
A回覆 B: 大佬,這樣可行,但是別的服務須要受權的時候怎麼辦
C回覆 B: 我認爲本質上就是這個思路,cloud裏面每一個頁面上的請求都要通過網關轉發一次,那也要有網絡延遲了,沒辦法。適當加上緩存吧,不用每次都去請求server判斷權限
-----------------------但願能夠幫助到你麼