基於SSM框架的通用權限框架設計spring
15數據庫
16緩存
17安全
小米筆記本服務器
權限設計主要有一下幾大部分組成:
PassPort:
針對如今系統的分析,系統之間有部分信息是共享的,這部分信息將由中心話的Passport來統一維護數據結構
權限訂閱模塊:
負責訂閱接受Passport發出的相關實體修改的信息。
資源權限綁定:
有效的將資源-角色-組-成員在數據庫中簡歷綁定。
數據權限高速內存數據緩存:
將數據權限相關的數據緩存在內存,提供高性能訪問能力。
Struts頁面權限過濾和綁定:
使用Struts的tag動態根據資源權限的設置,決定頁面中資源(按鈕,菜單,URL,頁面元素)的訪問能力。
數據權限過濾:
根據數據過濾權限的特定,定義的數據權限過濾的通用數據結構。
根據業務集成和整合的須要,和優先級別的須要,權限部分的開發設計將逐步推動,初期會以各應用系統爲單元進行資源權限和數據權限的改造,隨後將根據重要業務系統的須要,逐步創建中心話的passport。架構
資源權限綁定概覽app
資源:
菜單,按鈕,URL,頁面中的任何元素。
角色:
根據業務定義的各類角色,好比訂單生成角色,結算角色等。
組:
用於聯繫角色和用戶。
用戶:
系統中登陸的用戶。框架
(2)資源權限在開發,測試,項目上線後維護中的不一樣做用:運維
項目開發和測試階段:
在項目上線以後和運維階段:
分組和角色分別都有兩種類型,一種是管理類型,一種是普通類型,如下作詳細說明:
分組表設計(Group)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
功能級受權的意義在於對頁面可見元素的操做性,單純從頁面的可見性可簡單劃分紅以下幾個部分:
以上三點其實均可以歸結爲第三點,即:任何頁面可見的元素都可歸入功能級權限管理。
實現方法:採用自寫JSP標籤完成,執行該標籤時須要從後臺或緩存中查找當前用戶是否有使用當前資源的權限,若是有則正常顯示,若是沒有則將標籤內全部內容從服務端剔除後再響應客戶端。以下圖:
資源權限流程
publicclassAuthTagextendsStrutsBodyTagSupport{
private Set<String>authCodeSet;
publicvoidsetCode(String code) {
String[] codes = code.split(",");
authCodeSet = newHashSet<String>(Arrays.asList(codes));
}
publicintdoStartTag() throwsJspException {
HttpSessionhttpSession = pageContext.getSession();
Authentication authentication = (Authentication)httpSession.getAttribute(SessionSecurityConstants.KEY_AUTHENTICATION);
if(authentication == null){
returnSKIP_BODY;
}
if(hasAuth(authentication)){
returnEVAL_BODY_INCLUDE;
}
returnSKIP_BODY;
}
privatebooleanhasAuth(Authentication authentication){
for(String auth: authCodeSet){
if(authentication.getComponentResources().contains(auth)){
returntrue;
}
}
returnfalse;
}
}
頁面元素的可見性並不能控制URL的可訪問性,在系統設計中,使用Struts2的攔截器機制來過濾URL,防止用戶不經過頁面直接經過URL訪問系統。
系統資源的抽取設計。
系統資源包含了以上提到的兩個部分頁面元素和URL,兩種資源在某些時候是可組合的,好比按鈕點擊後提交URL,則該按鈕與該URL可組成一個資源。
頁面元素可獨立成爲一個資源,而URL不能脫離頁面元素獨立成爲資源。每一個資源都有惟一的標標識。
資源與資源之間也存在層級關係,好比下圖:
|
|
|
|
|
|
|
|
|
|
|
描述或備註信息 |
Key值的設定建議採用會意的字符串,好比新增按鈕資源屬於第三級資源則它的代碼應該爲"sysres_duty_add".
對資源的受權採用ZTree插件實現,效果見下圖:
對資源進行管理的樹狀插件
<%@ taglib prefix="hop" uri="/restree" %>
<res:treeurl="resTree.action"
expandUrl="expandResTree.action"
async="true"
chkType="check"
id="demoTree"/>
數據權限業務關鍵字定義
崗碼大致結構
崗碼的格式規則
崗碼格式以下:
崗位ID_崗位類型(管理/業務)_崗位職位_工貿ID_渠道ID_經營體ID_產品線code_BUCode_品牌_型號經營體.
注意:根據業務須要,崗碼會不斷的擴充,以存儲更多用於分析查詢的信息.
崗碼生成和崗碼從數據庫刷新至業務服務器
定時更新策略
天天定時執行崗碼更新SQL腳本,更新數據庫中的崗碼,而且定時重置內存中的數據緩存。這裏建議採用增量式更新,不然對數據庫壓力過大。這裏所使用的SQL腳本可參考下面第2點實時更新策略所使用的腳本。
實時更新策略
對於更新相對較頻繁的表(如人員表、崗位表),首先在該表上設立觸發器,基於表作的全部修改將記錄到歷史表中,系統定時掃描歷史表,發現改動則執行SQL腳本更新崗碼,並更新緩存。這裏的更新指單條記錄的更新,非批量更新。
當藍色部分使用應用服務的時候能夠直接更新緩存,從而略過橙色部分活動圖。
歷史表ecc_oms.sys.his
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(1) 新增用戶-崗位關係表和崗位-用戶崗碼關係表:ecc_oms.sys_emp_code
Emp_id :用戶ID
Code_id:崗碼ID-對應ecc_oms.ecc_oms.sys_code表主鍵
(2) 崗位-客戶崗碼關係表:ecc_oms.ecc_oms.sys_cust_code
Cust_code:客戶code
Code_id:崗碼ID
系統啓動時,將全部崗碼涉及到的表所有讀取成JavaBean(不是持久化對象),放在緩存中。
/**********資源相關**********/
人員信息: ecc_oms.sys_employee
組織(部門信息)信息: ecc_oms.sys_org
職位信息: ecc_oms.duty_title
區域(工貿)基本信息-ecc_oms.sys_area_info
所屬產品線,產品系統的產品(型號)信息:ecc_fnd.product_v
產品線信息:ecc_fnd.product_line_v
大小渠道基本信息-ecc_fst.sales_channel_properties
崗位基本信息:ecc_fst.station_config
客戶關係信息 -ecc_customer.customer_info_v
BU信息表 -ecc_oms.sys_bu_info
BU與產品線對應關係表 -ecc_fnd.bu_product_group_pl
/*********受權相關*********/
--組織經營體: ecc_oms.SYS_ORG_SALECHANN
--組織產品線: ecc_oms.sys_org_prod
--組織職位: ecc_oms.org_duty_title
崗碼錶: ecc_oms.sys_station_config
用戶崗碼錶: ecc_oms.sys_emp_code
客戶崗碼錶: ecc_oms.sys_cust_code
經營體與小渠道關係信息(按產品線): ecc_fst.sales_channel_manager_relation
客戶信息表-二級區域與客戶關係表
主要類列表和簡單描述:
類/接口名 |
簡介 |
核心接口描述 |
CacheServiceFacade |
暴露給客戶端遠程調用的接口 |
1.根據用戶id和崗位查詢該用戶的客戶列表,返回結果集自動關聯客戶對應的產品線信息 |
DefaultCacheServiceFacade |
CacheServiceFacade的默認實現類,根據請求的崗位類型自動判斷查找客戶信息 |
|
CacheService |
從緩存中讀取數據的頂層接口,定義內存中數據的讀取接口 |
1.根據用戶id查找用戶信息 |
AbstractCacheService |
CacheService的抽象實現,讀取客戶數據的公共方法抽取在裏面 |
|
CacheServiceA |
AbstractCacheService的子類實現,爲MD_XSJL下單 門店銷售經理查找客戶邏輯 |
|
CacheServiceB |
AbstractCacheService的子類實現,BU表明下單 |
|
CacheService |
AbstractCacheService的子類實現,查詢權限信息實現 |
|
CacheLoader |
緩存加載器 |
1.將指定表的數據加載到內存中 |
DefaultCacheLoader |
CacheLoader接口的實現類 |
|
TableOperation |
對單表進行的操做接口,用戶往操做歷史裏插入記錄時單條更新/刪除緩存操做 |
1.根據操做記錄對緩存進行操做 |
AbstractTableOperation |
TableOperation的抽象實現,定義公共操做方法 |
|
BasGCustomerInfoTableOperation |
AbstractTableOperation類的子類,表示 |
|
ReloadTableCacheJob |
定時任務,從新載入主數據表到緩存,每小時執行一次 |
|
UpdateCacheJob |
根據操做歷史記錄,對緩存中的數據進行單條更新,每15分鐘執行一次 |
|
UpdateCodeJob |
定時任務,按期掃描崗碼歷史表ecc_oms.sys_his,調用存儲過程,觸發更新崗碼操做,每10分鐘執行一次 |
|
在客戶端調用的應用中定義一個springbean,以下:
<beanid="cacheServiceFacade"class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<propertyname="serviceUrl"value="http://127.0.0.1:8011/authentication/remoting/cacheServiceFacade"/><!--這個是服務器端暴露的遠程訪問地址-->
<propertyname="serviceInterface"value="com.ouc.oms.authentication.cache.manager.CacheServiceFacade"/><!--這個是遠程調用接口聲明 -->
</bean>
Java代碼調用:
CacheServiceFacadecacheServiceFacade =applicationContext.getBean("cacheServiceFacade",CacheServiceFacade.class);
Set<CustomerInfoC>customerInfos =cacheServiceFacade.findCustomerByEmpId(11712L,"PR");
//something else
將須要客戶端調用的接口方法添加在CacheServiceFacade類中,並編寫實現類。
客戶端調用根據實際狀況可進行調整,如下給出樣例
publicinterfaceCacheService {
/**
* 根據人員ID查找客戶
*/
public List<Integer>findCustomerByEmpId(int id);
1、PR下單
1.根據人員ID查找崗位ID
select ser.fst_submit_station_id – 崗ID
From ecc_fst.station_employee_relationser – 崗人關係表
where ser.employee_id = 46 – 登錄人員ID
and ser.enable_flag = 'T' – 有效標識
and ser.delete_flag = 'F' – 刪除標識
2.根據崗ID查到PR崗
selectsc.fst_submit_station_id, -- 崗位ID
sc.fst_submit_station_code, -- 崗位編碼
sc.fst_submit_station_name, -- 崗位名稱
sc.product_line_id, -- 產品線ID
sc.product_series_code-- 產品組(與產品線ID互斥,兩個列只有一個值有效,若產品組有效要根據該編碼轉換成產品線ecc_fnd.bu_product_group_pl)
Fromecc_fst.station_configsc-- 崗位信息表
wheresc.fst_submit_station_idin (92172, 91239, 91241) -- 崗位ID
andsc.fst_role_lookup_code = 'PR'-- 業務類型
andsc.enable_flag = 'T'-- 有效標識
andsc.delete_flag = 'F'-- 刪除標識
3.根據崗ID查找每一個崗所屬的客戶
select scr.fst_submit_station_id, – 崗ID
scr.customer_id – 客戶ID(Number列,有科學計數法的主鍵)
From ecc_fst.station_customer_relationscr
where scr.fst_submit_station_id in (92172, 91239, 91241) – 崗位ID
and scr.enable_flag = 'T' – 有效標識
and scr.delete_flag = 'F' – 刪除標識
4.根據客戶ID查找客戶屬性
selectciv.customer_code, -- 客戶編碼
civ.customer_name, -- 客戶名稱
civ.customer_flag, -- 客戶類型 SX:傘下 HS:海傘 NULL:正常客戶
civ.first_region_code,-- 市場經營體編碼
civ.dqd_code, -- 大渠道編碼
civ.xqd_code-- 小渠道編碼
fromecc_customer.customer_info_vciv-- 客戶信息表
whereciv.customer_idin (20090507033457) -- 客戶ID
1、門店銷售經理(MD_XSJL)下單
1.根據人員ID查找崗位ID
select ser.fst_submit_station_id – 崗ID
From ecc_fst.station_employee_relationser – 崗人關係表
where ser.employee_id = 6946 – 登錄人員ID
and ser.enable_flag = 'T' – 有效標識
and ser.delete_flag = 'F' – 刪除標識
2.根據崗ID查到PR崗
selectsc.fst_submit_station_id, -- 崗位ID
sc.fst_submit_station_code, -- 崗位編碼
sc.fst_submit_station_name, -- 崗位名稱
sc.product_line_id, - 產品線ID-
sc.product_series_code-- 產品組
Fromecc_fst.station_configsc-- 崗位信息表
wheresc.fst_submit_station_idin (92172, 91239, 91241) -- 崗位ID
andsc.fst_role_lookup_code = 'MD_XSJL'-- 業務類型
andsc.enable_flag = 'T'-- 有效標識
andsc.delete_flag = 'F'-- 刪除標識
3.根據崗ID查找每一個崗所屬的客戶
select scr.fst_submit_station_id, – 崗ID
scr.customer_id – 客戶ID(Number列,有科學計數法的主鍵)
From ecc_fst.station_customer_relationscr
where scr.fst_submit_station_id in (92172, 91239, 91241) – 崗位ID
and scr.enable_flag = 'T' – 有效標識
and scr.delete_flag = 'F' – 刪除標識
4.根據客戶ID查找客戶屬性
selectciv.customer_code, -- 客戶編碼
civ.customer_name, -- 客戶名稱
civ.customer_flag, -- 客戶類型 SX:傘下 HS:海傘 NULL:正常客戶
civ.first_region_code,-- 市場經營體編碼
civ.dqd_code, -- 大渠道編碼
civ.xqd_code-- 小渠道編碼
fromecc_customer.customer_info_vciv-- 客戶信息表
whereciv.customer_idin (20090507033457) -- 客戶ID
1、 BU表明下單(BU_WGG_1,BU_WGG_2,BU_ACG,BU_DPG,BU_LE,BU_LF)下單
1.根據人員ID查找崗位ID
select ser.fst_submit_station_id – 崗ID
From ecc_fst.station_employee_relationser – 崗人關係表
where ser.employee_id = 6946 – 登錄人員ID
and ser.enable_flag = 'T' – 有效標識
and ser.delete_flag = 'F' – 刪除標識
2.根據崗ID查到PR崗
selectsc.fst_submit_station_id, -- 崗位ID
sc.fst_submit_station_code, -- 崗位編碼
sc.fst_submit_station_name, -- 崗位名稱
sc.product_line_id, - 產品線ID-
sc.product_series_code – 產品組
Fromecc_fst.station_configsc-- 崗位信息表
wheresc.fst_submit_station_idin (92172, 91239, 91241) -- 崗位ID
andsc.fst_role_lookup_codein (BU_WGG_1,BU_WGG_2,BU_ACG,BU_DPG,BU_LE,BU_LF)-- 業務類型
andsc.product_line_id = 777
andsc.enable_flag = 'T'-- 有效標識
andsc.delete_flag = 'F'-- 刪除標識
3.根據崗ID查找每一個崗所屬的品牌
selectscp.pro_value, -- 品牌標識
scp.pro_remark-- 品牌名稱
fromecc_fst.station_config_propertyscp
wherescp.fst_submit_station_id = 92349
andscp.delete_flag = '0'
4.根據崗位ID查找二級區域(網格)
selectst.sale_area_code, -- 區域編碼
st.sale_area_name-- 區域名稱
Fromecc_fnd.sale_area_station_infost-- 崗區關係表
wherest.station_config_id = 92349-- 崗位ID
andst.product_line_id = 777-- 產品線ID 1169用777表明
andst.enable_flag = 'T'
andst.delete_flag = 'F'
5.根據區域編碼查找區域信息
selectmkt.area_code, -- 區域編碼
mkt.area_name, -- 區域名稱
mkt.mkt_lookup_type-- 市場級別 S:社區店 T:專賣店
Fromecc_fnd.mkt_area_infomkt-- 區域信息表
wheremkt.area_code = 'CMI35899'-- 區域編碼
andmkt.enable_flag = 'T'
andmkt.product_line_id = 777-- 產品線ID
下接...
6.根據區域編碼查顆粒度
selectsur.small_unit_id, -- 顆粒度ID
sur.small_unit_code-- 顆粒度編碼
Fromecc_fnd.sale_area_unit_relationsur-- 區域與顆粒度關係表
wheresur.area_code = 'CMI00069'-- 區域編碼
andsur.product_line_id = 777-- 產品線ID 1169用777表明
andsur.enable_flag = 'T'
andsur.delete_flag = 'F'
7.根據顆粒度查客戶
selectciv.customer_code, -- 客戶編碼
civ.customer_name, -- 客戶名稱
civ.customer_flag, -- 客戶類型 SX:傘下 HS:海傘 NULL:正常客戶
civ.first_region_code,-- 市場經營體編碼
civ.dqd_code, -- 大渠道編碼
civ.xqd_code-- 小渠道編碼
fromecc_customer.customer_info_vciv-- 客戶信息表
whereciv.area_code = 'KLD2009000326'
/**
* 根據人員ID查找產品線
*/
public List<ProdC>findProdByEmpId(int id);
1.根據人員ID查找崗位ID
select ser.fst_submit_station_id – 崗ID
From ecc_fst.station_employee_relationser – 崗人關係表
where ser.employee_id = 6946 – 登錄人員ID
and ser.enable_flag = 'T' – 有效標識
and ser.delete_flag = 'F' – 刪除標識
2.根據崗ID查到PR崗
selectsc.fst_submit_station_id, -- 崗位ID
sc.fst_submit_station_code, -- 崗位編碼
sc.fst_submit_station_name, -- 崗位名稱
sc.product_line_id, -- 產品線ID
sc.product_series_code-- 產品組(與產品線ID互斥,兩個列只有一個值有效,若產品組有效要根據該編碼轉換成產品線ecc_fnd.bu_product_group_pl)
Fromecc_fst.station_configsc-- 崗位信息表
wheresc.fst_submit_station_idin (92172, 91239, 91241) -- 崗位ID
andsc.fst_role_lookup_code = 'PR'-- 業務類型
andsc.enable_flag = 'T'-- 有效標識
andsc.delete_flag = 'F'-- 刪除標識
若產品組有效要根據該編碼轉換成產品線
selectp.product_code, -- 產品線編碼
p.product_id, -- 產品線ID
p.product_name, -- 產品線名稱
p.group_code-- BU編碼
Fromecc_fnd.bu_product_group_plp-- 產品BU對照表
wherep.group_code = 'WGG01'-- BU編碼
2.2.若產品線不爲空
selectplv.PRODUCT_ID, -- 產品ID
plv.PRODUCT_CODE, -- 產品編碼
plv.PRODUCT_LINE_NAME-- 產品名稱
Fromecc_fnd.product_line_vplv-- 產品線表
whereplv.PRODUCT_ID = 100000-- 產品線ID
2.3.BU表明下單的場合BU_WGG_1,BU_WGG_2,BU_ACG,BU_DPG,BU_LE,BU_LF
selectb.product_id, -- 產品線ID
b.product_code, -- 產品線編碼
b.product_name-- 產品線名稱
Fromecc_fnd.bu_product_groupb-- BU與產品線關係表
whereb.group_code = 'BU_WGG_1'-- BU編碼
/**
* 根據人員ID查找經營體
*/
public List<SalechannC>findScalByEmpId(int id);
1.根據人員ID查經營體ID
selectom.sale_manager_id, -- 經營體ID
om.sale_manager_code-- 經營體編碼
FromECC_OMS.SYS_EMP_SALECHANNOM-- 人員經營體關係表
whereom.emp_id = 49485-- 人員ID
andom.enable_flag = 'T'
andom.delete_flag = 'F'
2.根據經營體ID或編碼查經營體名稱
select cm.sales_chan_manager_code, – 經營體編碼
cm.sales_chan_manager_name – 經營體名稱
from ECC_FST.SALES_CHANNEL_MANAGER CM – 經營體信息表
where(cm.sales_chann_manager_id = 1 – 經營體ID
or cm.sales_chan_manager_code = '1001')-- 經營體編碼
andcm.enable_flag = 'T'
andcm.delete_flag = 'F';
/**
* 根據人員ID查找渠道
*/
public List<ChannelC>findChannelByEmpId(int id);
/**
* 根據人員ID查找工貿
*/
public List<AreaC>findAreaByEmpId(int id);
1.根據人員ID查工貿ID或編碼
selectam.area_id, -- 工貿ID
am.area_code-- 工貿編碼
FromECC_OMS.SYS_EMP_AREAAM-- 人區關係表
wheream.emp_id = 3549-- 人員ID
andam.enable_flag = 'T'
andam.delete_flag = 'F'
2.根據工貿ID或編碼查名稱(有兩個表)
selecta.area_code, -- 工貿編碼
a.area_name-- 工貿名稱
fromECC_OMS.SYS_AREA_INFOa-- 工貿信息表
where (a.area_id = 519-- 工貿ID
ora.area_code = '12C01') -- 工貿編碼
anda.enable_flag = 'T'
anda.delete_flag = 'F'
selectmkt.area_code, -- 工貿編碼
mkt.area_name-- 工貿名稱
fromecc_fnd.mkt_area_infomkt-- 區域信息表
wheremkt.area_code = '12C01'-- 工貿編碼
andmkt.enable_flag = 'T'
/**
* 根據人員ID查找產品線
*/
public List<CustomerC>findCustByEmpId(int id);
1.根據人員查產品線ID和編碼
select sep.prod_id, – 產品線ID
sep.prod_code – 產品線編碼
from ecc_oms.sys_emp_prodsep – 人員產品線關係表
where sep.emp_id = 11433 – 人員ID
andsep.enable_flag = 'T'
andsep.delete_flag = 'F'
2.根據產品線ID或產品線編碼查名稱
selectplv.PRODUCT_CODE, -- 產品線編碼
plv.PRODUCT_LINE_NAME-- 產品線名稱
Fromecc_fnd.product_line_vplv-- 產品線信息表
where (plv.PRODUCT_ID = 100000-- 產品線ID
orplv.PRODUCT_CODE = 'AA') -- 產品線編碼
/**
* 根據客戶ID查找人員
*/
public List<Integer>findEmpByCustId(int id);
根據findCustomerByEmpId反向查