




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、在項目中集成shiro權限框架(1) Shiro是一個功能強大的輕量級權限框架,相對其它權限框架(比如spring security)來說,要易用得很,下面,我給大家講講如何在一個項目中簡單整合shiro。我們通常所說的權限,就是要判斷某個操作者是否有操作某個資源的權限,而資源,可以是菜單、鏈接、功能按鈕、業務方法、某類型的數據等等,根據需求,每個項目的權限可能都有所不同,通用萬能權限系統是不存在的。 Shrio的權限包括認證、授權、密碼管理、會話管理等四個部分,每一個部分,shrio都進行了抽象,以做到和具體應用平臺、環境的無關。關于shiro的基礎了解,大家可
2、到這里去看看:權限系統的設計,根據不同的權限粒度,會用所不同,比如:有的系統到菜單級,而有的到每一個功能按鈕級,有的到方法級,有的到業務數據級,我在這僅僅討論前兩類。 上面是一個對象關系圖,模塊在此處僅僅為菜單進行邏輯歸類,當然,也可以建立菜單和功能的一對多關系,為功能進行邏輯歸類。當然,菜單也可以建成關聯的樹狀結構,以更好擴展。 根據對象關系,可以設計出表結構,我直接貼出數據截圖:模塊表:菜單表: 操作表,一般對應頁面中的按鈕,其中f_action_flag對應于restful中的增、刪、查、改: 角色表: 角色-菜單關系表: 角色
3、-功能表: 用戶表: 用戶-角色關系表: 上面截圖中,真正有效的表7張,權限控制到頁面及功能上。下篇,貼出上面的類代碼及class映射文件。在項目中集成shiro權限框架(2)基礎代碼貼上:對象如下:/* * 用戶對象 * * authorLjh * */public classUser implementsSerializable / 學生編碼(由系統自動生成)
4、; privateLong id; / 姓名 NotEmpty(message = "姓名不可以為空!") Length(min = 2, max = 5) privateString name;
5、60;/ 出生日期 NotNull(message = "生日不能為空") Past(message = "生日輸入不正確,請核對!") privateDate birthday; / 登錄密碼 privateString passwor
6、d= "111" / 用戶角色集合字符 privateSet<Role> roles= newHashSet<Role>(); /* * 得到該用戶可訪問的模塊,模塊中的菜單將實例化 *
7、60;return */ publicList<Model> getModels() List<Model> models = newArrayList<Model>(); for(Iterator<Menu> its
8、160;= this.getMenus().iterator(); its.hasNext();) Menu m = its.next(); if(!models.contains(m.getModel()
9、 Model model = newModel(); model.setId(m.getModel().getId(); model
10、.setDisplayOrder(m.getDisplayOrder(); model.setModelName(m.getModel().getModelName(); model.getMenus().add(m);
11、 models.add(model); else for(Model model : models)
12、0; if(model.getId() = m.getModel().getId() model.getMenus().add(m);
13、60; break;
14、60; Collections.sort(models); returnmodels; &
15、#160; /* * 得到用戶可訪問的菜單資源 * return */ publicSet<Menu> getMenus() Set<Menu> menus = new
16、HashSet<Menu>(); for(Iterator<Role> role = this.getRoles().iterator(); role.hasNext();) menus.addAll(role.next().getMenus();
17、160; returnmenus; / 用戶菜操作功能權限集合字符串描述 publicSet<String> getOperationPermissionsAsString() &
18、#160; Set<String> pomissions = newHashSet<String>(); Iterator<Role> roles = this.getRoles().iterator(); &
19、#160;Operation op; Map<String, HashSet<String>> p_map = newHashMap<String,HashSet<String>>();
20、60; while(roles.hasNext() Iterator<Operation> operations =roles.next().getOperations().iterator(); while(operations.hasNext()
21、 op = operations.next(); String key = op.getUrl();
22、; if(!key.startsWith("/") key = "/"+ key;
23、0; if(p_map.get(key) = null) p_map.put(key, newHashSet<String>();
24、 p_map.get(key).add(op.getActionFlag();
25、0; /構建形如:doc:read, moveuser:modify, users:read,user:modify,read,create的權限字串 for(Entry<String, HashSet<String> > entry :p_map.entrySet()
26、; pomissions.add(entry.getKey() + ":"+ entry.getValue().toString().replace("", "").replace("", "").replace(" ", "");
27、160; returnpomissions; / 用戶菜單權限集合字符串描述/ public Set<String> getMenuPermissionsAsString() / Set<String> pomissions= newH
28、ashSet<String>();/ Iterator<Role> roles = this.getRoles().iterator();/ while (roles.hasNext() / Iterator<Menu> menus =roles.next().getMe
29、nus().iterator();/ while (menus.hasNext() / pomissions.add(menus.next().getCode();/ /
30、0;/ return pomissions;/ /* * 得到我的全部權限 * return */ publicSet<String> getPermissionsAsString()
31、160; Set<String> permissions = newHashSet<String>(); /permissions.addAll(getMenuPermissionsAsString(); permissions.addAll(getOperationPermissionsAsString();
32、 return permissions; / 得到用戶角色字符串描述 publicSet<String> getRolesAsString() Set<String> str_roles
33、;= newHashSet<String>(); Iterator<Role> roles = this.getRoles().iterator(); while(roles.hasNext() str_roles.add(rol
34、es.next().getRoleCode(); returnstr_roles; 角色對象: public classRole implementsSerializable /OID private int
35、id; /顯示名稱 privateString displayName; /角色編碼,用于生成權限框架的惟一標識 privateString roleCode; /角色可以操作的菜單 privateSet<Menu> menus= newHashSet<Menu&g
36、t;(); /角色可操作的操作功能【對應于增、刪、查、改等功能】 privateSet<Operation> operations= newHashSet<Operation>(); 菜單對象: public classMenu implementsResource, Comparable, Serializable &
37、#160; /OID private int id; privateString code; privateString name; /顯示順序 private int displayOrder; /url地址
38、0; privateString url; /所屬模塊 privateModel model; Override public intcompareTo(Object menu) Menu m = (Menu)menu;
39、; returnm.getDisplayOrder() - this.getDisplayOrder(); 操作功能對象:public classOperation implementsResource, Serializable /OID private int id; &
40、#160;/操作碼(保留待用) privateString code; /名稱 privateString name; /操作標志read:讀取,create:新增,modify:修改,delete:刪除 /在rest風格中,將請求方式映射為上述四種操作,設計為字符串,以方便今后擴展
41、60; privateString actionFlag; /操作url地址,比如:/user/* privateString url; /所屬菜單 privateMenu menu; /顯示順序,保留待用
42、160; private int displayOrder; 功能模塊對象:/* * 功能模塊 * authorAdministrator * */public classModel implementsComparable<Model>,Serializable /public class Model private int
43、60;id; privateString modelName; /顯示順序 private int displayOrder; privateSet<Menu> menus= newHashSet<Menu>(); 資源抽象對象,目前暫
44、未使用:/* * 資源抽象類 * authorAdministrator * */public interfaceResource /得到資源編碼 publicString getResCode(); 最后,貼上hbm文件。<classname="com.my.model.User"table="t_student">
45、; <idname="id"> <columnname="pk_id"/> <generatorclass="identity"><
46、/generator> </id> <propertyname="name"type="java.lang.String"> &
47、#160; <columnname="f_name"/> </property> <propertyname="password"type="java.lang.String">
48、0; <columnname="f_password"/> </property> <propertyname="birthday">
49、 <columnname="f_birthday"/> </property> <setname="roles"table="t_student_role">
50、160; <keycolumn="fk_student_id"></key> <many-to-manyclass="com.my.model.Role"column="fk_role_id"> &
51、lt;/many-to-many> </set></class> <classname="com.my.model.Model"table="t_model"> <idname="id">
52、160; <columnname="pk_id"/> <generatorclass="identity"></generator> </id> &
53、lt;propertyname="modelName"type="java.lang.String"> <columnname="f_model_name"/> </property>
54、60; <propertyname="displayOrder"column="f_display_order"> </property> <setna
55、me="menus"table="t_menu"order-by="f_display_order"> <keycolumn="fk_model_id"></key> <one-to-manyclass="com.my.model.Menu"/>
56、 </set> </class> <classname="com.my.model.Menu"table="t_menu"> <idname="id">
57、 <columnname="pk_id"/> <generatorclass="identity"></generator> </id>
58、; <propertyname="code"type="java.lang.String"> <columnname="f_code"/>
59、; </property> <propertyname="name"type="java.lang.String"> <columnname="f_name"/>
60、 </property> <propertyname="displayOrder"column="f_display_order"> </property> &
61、#160; <propertyname="url"type="java.lang.String"> <columnname="f_url"/>
62、60;</property> <many-to-onename="model"class="com.my.model.Model"column="fk_model_id"> </many-to-one> </class> &
63、#160; <classname="com.my.model.Operation"table="t_operation"> <idname="id"> <columnname="pk_id"/>
64、0; <generatorclass="identity"></generator> </id> <propertyname
65、="code"type="java.lang.String"> <columnname="f_code"/> </property> <propertyname=
66、"name"type="java.lang.String"> <columnname="f_name"/> </property>
67、 <propertyname="displayOrder"column="f_display_order"> </property> <propertyname="actionFlag&qu
68、ot;column="f_action_flag"> </property> <propertyname="url"type="java.lang.String"> &
69、#160; <columnname="f_url"/> </property> <many-to-onename="menu"class="com.my.
70、model.Menu"column="fk_menu_id"> </many-to-one> </class> <classname="com.my.model.Role"table="t_role">
71、160;<idname="id"> <columnname="pk_id"/> <generatorclass="identity"></generator> &
72、#160; </id> <propertyname="displayName"type="java.lang.String"> <columnname="
73、f_displayName"/> </property> <propertyname="roleCode"type="java.lang.String"> <columnn
74、ame="f_roleCode"/> </property> <setname="menus"table="t_role_menu"> <keycolumn="fk_role_id&quo
75、t;></key> <many-to-manyclass="com.my.model.Menu"column="fk_menu_id"order-by="f_display_order"> </many-to-many>
76、60; </set> <setname="operations"table="t_role_operation"> <keycolumn="fk_role_id"></
77、key> <many-to-manyclass="com.my.model.Operation"column="fk_operation_id"order-by="f_display_order"> </many-to-many>
78、0; </set> </class> 基礎的代碼完成了,其實,user中已經有部分和權限驗證相關的代碼了,后面我詳細講解。在項目中集成shiro權限框架(3)Shiro與spring已經有完整的整合方法,所以,我們先在web.xml中添對過濾器,將需要驗證的請求,攔截到shiro中。<!shiro過濾器-> <filter> <filte
79、r-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param>
80、0;<param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> &
81、lt;filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 在spring配置中添加下面的支持bean.<!- 權限or判定器->
82、;<beanid="roleOrFilter"class="mons.RolesOrFilter"> </bean> <!- 認證數據庫存儲-> <beanid="myRealm"class="com.my.service.impl.DbAuthRealm">
83、160; </bean> <!- 權限管理器-> <beanid="securityManager"class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <propertyname="realms">
84、0; <list> <refbean="myRealm"/> </list>
85、60; </property> </bean> <beanid="shiroFilter"class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"depends-on="roleOrFilter">
86、 <propertyname="securityManager"ref="securityManager"/> <propertyname="loginUrl"value="/login.jsp"/> <propertyname="successUrl"value="/ma
87、in"/> <propertyname="unauthorizedUrl"value="/commons/unauth.jsp"/> <!- 讀取自定義權限內容-> <pro
88、pertyname="filterChainDefinitions"value="#authService.loadFilterChainDefinitions()"/> <propertyname="filters"> <map>
89、60; <entrykey="roleOrFilter"value-ref="roleOrFilter"> </entry>
90、0; </map> </property> </bean> <beanid="lifecycleBeanPostProcessor"class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> 其中filterChainD
91、efinitions部分,簡單的項目可以直接寫死,我們這里采用的是啟動時讀取生成,如果寫死,將會出現類似下面的代碼:<property name="filterChainDefinitions"> <value> /js/* =
92、anon /css/* = anon /login.jsp = anon
93、 /login = anon /docs/doc1.jsp= authc,roleOrFilteradmin,dev /admin/manager.jsp = authc, roleOrFilter
94、admin /admin/user/* = authc, rest/admin/user/* /userinfo/myinfo.jsp = authc,roleOrFiltertest,dev,admin &
95、#160; /* = authc </value> </property> 這段靜態權限代碼中用到了過濾器,我得給大家說一下:anon部分是不需要進行驗證的,即這部分是要放行的(注意*與*是有
96、區別的,*表示該目錄下的所有,當然也包括子目錄下的東西,而*僅指當前目錄下的東西)。Authc,這個是需要登錄的人才可以訪問的。roleOrFile,這個是我定義的,只要這個過濾器中的一個角色滿足,即可訪問,而shiro提供的role過濾器,是當所有角色都滿足時才可訪問。Rest是restful過濾器,會將get,post,put,delete轉換為對資源的read.create,modify,delete操作。當然,shiro還提供了其它的過濾器,大家可以自己去看看,比如:permission過濾器,shiro對權限的描述采用wildcard字串,功能強大且可讀性強。另外一點要接出,shir
97、o在里使用最先匹配規則,一旦匹配成功,將不再進行后續的過濾規則檢查,因此,在書寫時一定要注意順序,比如,你把/* = anon寫到第一行,那么后面的一切都將不會再檢測。好了,下面來講如何動態生成這個規則,大家看我的配置中有value="#authService.loadFilterChainDefinitions()",這個是spring el表達式語言,表示調用容器中的另一個bean的方法,把這個方法的返回結果,賦值給filterChainDefinitions屬性。在些再補充一些權限字串的知識:shiro所支持的廣義權限字串表達式,共有三種
98、:1、簡單方式比如:subject.isPermitted("editNews"),表示判斷某操作者是否有【編輯新聞】的權限。2、細粒度方式比如:subject.isPermitted("News:create"),表示判斷某操作者是否有【新建新聞】的權限。3、實例級訪問方式比如:subject.isPermitted("News:edit:10"),表示判斷某操作者是否有【編輯id號是10新聞】的權限。上面3種方式中,可以用*表示所有,例如:"News:*"為對所有新聞的操作,"*:create&quo
99、t;對所有事務都可以新增。還可以用 逗號 表示或都,"News:edit:10,11"表示可對10,11號新聞進行編輯。如果要寫頁面權限,可參照如下配置:/index.jsp = anon/admin/* = authc, rolesadmin /docs/* = authc, permsdocument:read /* = authc 我定義了一個權限相關的接口,如下:/* * 權限管理相關方法
100、;* authorljh * */public interfaceIAuthService /* * 加載過濾配置信息 * return */ publicString loadFilterChainDefinitions();
101、 /* * 重新構建權限過濾器 * 一般在修改了用戶角色、用戶等信息時,需要再次調用該方法 */ public voidreCreateFilterChains(); 其中一個方法用于加載生成權限規則字串,另一個,用于用戶在系統中更改了角色-菜單,角色-功能
102、關系時,動態重新生效的方法,實現類如下:Service(value="authService")public classAuthServiceImplimplementsIAuthService private static finalLogger log= Logger.getLogger(AuthServiceImpl.class);
103、 /注意/r/n前不能有空格 private static finalString CRLF= "rn" private static finalString LAST_AUTH_STR= "/* =authcrn" Resource
104、160;privateShiroFilterFactoryBean shiroFilterFactoryBean; Resource privateIBaseDao dao; Override publicString loadFilterChainDefinitions() &
105、#160; StringBuffer sb = newStringBuffer(""); sb.append(getFixedAuthRule() .append(getDynaAuthRule()
106、; .append(getRestfulOperationAuthRule() .append(LAST_AUTH_STR); returnsb.toString(); /生成
107、restful風格功能權限規則 privateString getRestfulOperationAuthRule() List<Operation> operations = dao.queryEntitys("from Operation o", newObject);
108、 Set<String> restfulUrls = newHashSet<String>(); for(Operation op : operations) &
109、#160; restfulUrls.add(op.getUrl(); StringBuffer sb = newStringBuffer(""); for(Iterator<String> urls = restf
110、ulUrls.iterator(); urls.hasNext(); ) String url = urls.next(); if(! url.startsWith("/") &
111、#160; url = "/"+ url sb.append(url).append("=").append("authc, rest&quo
112、t;).append(url).append("").append(CRLF); returnsb.toString();
113、160; /根據角色,得到動態權限規則 privateString getDynaAuthRule() StringBuffer sb = newStringBuffer("");
114、60;Map<String, Set<String>> rules = newHashMap<String,Set<String>>(); List<Role> roles = dao.queryEntitys("from Role r left joi
115、n fetch r.menus", newObject); for(Role role: roles) for(Iterator<Menu> menus =role.getMenus().iterator(); menus.hasNext();)
116、160; String url = menus.next().getUrl(); if(!url.startsWith("/")
117、60; url = "/"+ url; if(!rules.containsKey(url)
118、60; rules.put(url, newHashSet<String>();
119、0; rules.get(url).add(role.getRoleCode(); for(Map.Entry<String, Set<String>>
120、; entry :rules.entrySet() sb.append(entry.getKey().append(" = ").append("authc,roleOrFilter").append(entry.getValue().append(CRLF);
121、0; returnsb.toString(); /得到固定權限驗證規則串 privateString getFixedAuthRule() &
122、#160; StringBuffer sb = newStringBuffer(""); ClassPathResource cp = newClassPathResource("fixed_auth_perties");
123、160; Properties properties = newOrderedProperties(); try properties.load(cp.getInputStream(); catch(IOE
124、xception e) log.error("loadfixed_auth_perties error!", e); throw newRuntimeException("load fixed_auth_perties&
125、#160;error!"); for(Iteratorits = properties.keySet().iterator();its.hasNext();) String key = (String)its.next();
126、0; sb.append(key).append(" = ").append(properties.getProperty(key).trim().append(CRLF); returnsb.toString(); Override
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 山西華澳商貿職業學院《臨床檢驗儀器》2023-2024學年第二學期期末試卷
- 濟南護理職業學院《嵌入式課程設計》2023-2024學年第二學期期末試卷
- 臨床免疫學檢驗課件 第3章 免疫原和抗血清的制備學習資料
- 西安海棠職業學院《隸書》2023-2024學年第一學期期末試卷
- 江蘇農牧科技職業學院《硬筆書法》2023-2024學年第一學期期末試卷
- 鹽城工業職業技術學院《工商管理級學碩》2023-2024學年第二學期期末試卷
- 二零二五版資金監管委托協議樣本
- 二零二五全新美食城檔口出租協議
- 二零二五版學生托人接送免責協議書范文
- 游戲開發回顧與展望
- 產品QC工程圖 (質量保證工程圖)Excel表格
- 人民醫院人才隊伍建設規劃人才隊伍建設五年規劃
- 電氣平行檢驗用表
- GB∕T 14527-2021 復合阻尼隔振器和復合阻尼器
- 一年級語文下冊課件-21 小壁虎借尾巴24-部編版(15張PPT)
- 患者隨訪率低原因分析以及對策
- DB32∕T 2349-2013 楊樹一元立木材積表
- 首屆上海科技期刊編輯技能大賽試題
- 隧道二襯、仰拱施工方案
- Q∕GDW 12106.4-2021 物聯管理平臺技術和功能規范 第4部分:邊緣物聯代理與物聯管理平臺交互協議規范
- 中國癲癇診療指南-癲癇持續狀態課件
評論
0/150
提交評論