關於AOP攔截器使用的一個問題,尋求解決方案
最近我在設計通用許可權元件的時候遇到AOP攔截器方面的一個問題,尋求解決方案,先描述一下應用場景:
通用許可權元件以AOP的形式“插入”業務系統,AOP的攔截機制有兩種:
(A)透過Filter對使用者請求的URI進行攔截
(B)透過Interceptor對使用者呼叫的服務介面進行攔截
例子如下:
某業務系統有A、B兩大模組,分別提供兩大型別的服務,A、B兩個模組都包含了若干的服務介面方法:
public interface AService {
public void a1() throws ServiceException;
public void a2() throws ServiceException;
}
public interface BService {
public void b1() throws ServiceException;
public void b2() throws ServiceException;
}
為了實現以Interceptor的方式進行服務介面方法攔截,以實現許可權控制,需求在許可權系統把每個服務介面方法都進行註冊,使其成為受控資源實體:
com.xxx.AService.a1
com.xxx.AService.a2
com.xxx.BService.b1
com.xxx.BService.b2
然後把這些實體分配給角色,例如:
Role1:com.xxx.AService.a1
Role2:com.xxx.AService.a1;com.xxx.AService.b1
問題出現了,請看服務的實現類
public class AServiceImpl implements AService {
private BService bService;
public void a1() thorws ServiceException() {
// Business logic
bService.b1();
// Other business logic
...
}
...
}
由於服務A.a1的某些業務邏輯與服務B.b重複了,合理的設計是,把B作為成員變數注入到A中,並且A以介面的方式使用B(如上述程式碼片斷),但由於實際的需要,某個角色Role1只能訪問a1服務,無權訪問b1服務,由於使用了AOP的攔截器方式,Role1在訪問AService.a1()的時候,攔截器把這個動作攔截下來,判斷Role1發現他擁有AService.a1()的呼叫權,本次攔截透過,Role1順利的呼叫了a1()方法,但隨即,a1()呼叫了BService.b1()方法,這時候攔截器再次對Role1進行許可權判斷,發現Role1並沒有b1()的呼叫權,最終,本次呼叫被拒絕。但實際上,從使用者的角度考慮,使用者不應該知道實現細節,他在配置許可權的時候,只關心業務,我們不可能要求使用者要從技術角度去知道a1本身呼叫了b1。
上述的情況不常見,因為如果使用者擁有a1的使用權,而a1本身又需要b1提供服務,正常的情況下該使用者應該同時擁有a1、b1的使用權,但事實可能真的會存在上述的情況,我想到的其中一種辦法是:
在AService、BService的“前面”增加一個Facade(門面),許可權攔截器攔截這個Facade,而不是攔截直接AService和BService。
其實這樣的設計是合理的,雖然為系統增加了一個“層”,但這個“層”剛好把系統抽象的分離為“對外服務介面”和“對內服務介面”了,服務之間的呼叫,直接使用Service介面,外部訪問系統,使用Facade介面,整個系統的設計更加合理和清晰,靈活性也更強。
但同時我又必須考慮一個問題:我設計的是一個通用的許可權元件,為了儘可能通用,元件必須能最大限度適應外界的各種情況,而且,通用元件不可能要求外部系統必須要使用這種“Facade Pattern”,如果是這樣的話,不但加大了對外部使用者的限制,而且會讓外部系統與許可權元件形成“迴圈依賴”,因為許可權元件不得不依賴於外部系統提供Facade。
本人對AOP的概念理解或者算是比較清晰,但對於AOP的技術實現(Spring AOP、AspectJ等)並不精通,請教一下各位,有沒有更好的解決方案呢?
通用許可權元件以AOP的形式“插入”業務系統,AOP的攔截機制有兩種:
(A)透過Filter對使用者請求的URI進行攔截
(B)透過Interceptor對使用者呼叫的服務介面進行攔截
例子如下:
某業務系統有A、B兩大模組,分別提供兩大型別的服務,A、B兩個模組都包含了若干的服務介面方法:
public interface AService {
public void a1() throws ServiceException;
public void a2() throws ServiceException;
}
public interface BService {
public void b1() throws ServiceException;
public void b2() throws ServiceException;
}
為了實現以Interceptor的方式進行服務介面方法攔截,以實現許可權控制,需求在許可權系統把每個服務介面方法都進行註冊,使其成為受控資源實體:
com.xxx.AService.a1
com.xxx.AService.a2
com.xxx.BService.b1
com.xxx.BService.b2
然後把這些實體分配給角色,例如:
Role1:com.xxx.AService.a1
Role2:com.xxx.AService.a1;com.xxx.AService.b1
問題出現了,請看服務的實現類
public class AServiceImpl implements AService {
private BService bService;
public void a1() thorws ServiceException() {
// Business logic
bService.b1();
// Other business logic
...
}
...
}
由於服務A.a1的某些業務邏輯與服務B.b重複了,合理的設計是,把B作為成員變數注入到A中,並且A以介面的方式使用B(如上述程式碼片斷),但由於實際的需要,某個角色Role1只能訪問a1服務,無權訪問b1服務,由於使用了AOP的攔截器方式,Role1在訪問AService.a1()的時候,攔截器把這個動作攔截下來,判斷Role1發現他擁有AService.a1()的呼叫權,本次攔截透過,Role1順利的呼叫了a1()方法,但隨即,a1()呼叫了BService.b1()方法,這時候攔截器再次對Role1進行許可權判斷,發現Role1並沒有b1()的呼叫權,最終,本次呼叫被拒絕。但實際上,從使用者的角度考慮,使用者不應該知道實現細節,他在配置許可權的時候,只關心業務,我們不可能要求使用者要從技術角度去知道a1本身呼叫了b1。
上述的情況不常見,因為如果使用者擁有a1的使用權,而a1本身又需要b1提供服務,正常的情況下該使用者應該同時擁有a1、b1的使用權,但事實可能真的會存在上述的情況,我想到的其中一種辦法是:
在AService、BService的“前面”增加一個Facade(門面),許可權攔截器攔截這個Facade,而不是攔截直接AService和BService。
其實這樣的設計是合理的,雖然為系統增加了一個“層”,但這個“層”剛好把系統抽象的分離為“對外服務介面”和“對內服務介面”了,服務之間的呼叫,直接使用Service介面,外部訪問系統,使用Facade介面,整個系統的設計更加合理和清晰,靈活性也更強。
但同時我又必須考慮一個問題:我設計的是一個通用的許可權元件,為了儘可能通用,元件必須能最大限度適應外界的各種情況,而且,通用元件不可能要求外部系統必須要使用這種“Facade Pattern”,如果是這樣的話,不但加大了對外部使用者的限制,而且會讓外部系統與許可權元件形成“迴圈依賴”,因為許可權元件不得不依賴於外部系統提供Facade。
本人對AOP的概念理解或者算是比較清晰,但對於AOP的技術實現(Spring AOP、AspectJ等)並不精通,請教一下各位,有沒有更好的解決方案呢?
[該貼被johnnylzb於2008-02-19 17:21修改過]
相關文章
- CMP DataSource問題,尋求解決方案
- 關於寫死namespace與攔截器結合使用導致死迴圈的問題namespace
- flume自定義攔截器遇到的問題
- 關於網站安全狗解除安裝了仍然能攔截的問題解決網站
- 解決在.net8 WebAPI中 使用AbstractInterceptorAttribute 實現AOP 攔截器WebAPI
- AOP程式設計--Filter使用,過濾器和攔截器的區別程式設計Filter過濾器
- Spring MVC 中的攔截器的使用“攔截器基本配置” 和 “攔截器高階配置”SpringMVC
- 解決spring cloud Feign遠端呼叫服務,新增headers解決攔截器攔截問題SpringCloudHeader
- Spring AOP 日誌攔截器的事務管理Spring
- spring mvc攔截器,spring攔截器以及AOP切面的區別和原始碼SpringMVC原始碼
- 基於原生fetch封裝一個帶有攔截器功能的fetch,類似axios的攔截器封裝iOS
- 求解決 Laravel with () limit 的問題 附帶解決方案LaravelMIT
- 求解spring aop cglib問題SpringCGLib
- 一個關於/root/.gvfs的問題解決?
- 攔截器,攔截器棧總結
- 從源頭上解決微信域名攔截問題
- spring攔截器的一個簡單例子Spring單例
- spring mvc 攔截器的使用SpringMVC
- 使用window.open開啟新視窗被瀏覽器攔截的解決方案瀏覽器
- 手擼了一個HTTP框架:支援Sprng MVC、IOC、AOP,攔截器,配置檔案讀取...HTTP框架MVC
- 一個小問題的解決方案
- 自定義攔截器,攔截到了某個請求就返回給前端一個JSON串前端JSON
- 關於教程的一個問題
- 關於Cordova框架對URL攔截導致通訊丟失問題的處理框架
- 關於搜尋地址的問題
- 關於 django-ckeditor 前段使用的一個問題Django
- 基於node Express 攔截器的實現Express
- axios 攔截器 的使用方法iOS
- Spring Boot中攔截器的使用Spring Boot
- SpringMVC攔截器的使用場景SpringMVC
- 使用攔截器的方法過濾特性
- SSL攔截-加密流量審查解決方案加密
- SpringMVC攔截器,設定不攔截的URLSpringMVC
- 高手都進來歇歇~解決一個問題關於SE的問題
- 一個關於ace-editor編輯器的問題
- 關於解決問題的幾個段位
- 分享關於我做微信行銷推廣時遇到的難題-域名頻繁被攔截圖蔽的解決方案
- MyBatis攔截器MyBatis