日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

在Spring MVC中使用Apache Shiro安全框架

發布時間:2025/3/21 javascript 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在Spring MVC中使用Apache Shiro安全框架 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我們在這里將對一個集成了Spring MVC+Hibernate+Apache Shiro的項目進行了一個簡單說明。這個項目將展示如何在Spring MVC 中使用Apache Shiro來構建我們的安全框架。

[TOC]

閱讀文章前,您需要做以下準備:

  • Maven 3環境
  • Mysql-5.6+
  • JDK1.7+
  • git環境
  • git.oschina.net帳號
  • Apache Tomcat 7+
  • 您熟練掌握的編輯工具,推薦使用InterlliJ IDEA 14+

開始

項目地址git.oschina.net

項目地址github.com

安全管理框架數據結構

首先,我們在mysql數據庫中創建schema,命名為shirodemo。我們在創建兩個用戶shiroDemo@localhost和shiroDemo@%,這里我們將用戶的密碼簡單設置成123456。

然后,我們將項目從git服務器上clone到本地后,我們可以在項目根目錄下的resources中發現db.sql文件。這個文件是項目的數據庫結構文件,你可以將db.sql導入到數據庫shirodemo中。

我們這里的權限結構設計比較簡單,我們以表格的形式說明主要數據庫結構:

**Table:t_user**

Name Type Length Describ
id int 11 用戶表的主鍵
password varchar 255 密碼
username varchar 255 用戶名,全局唯一,shiro將使用用戶名來鎖定安全數據中的用戶數據。

**Table:t_role**

Name Type Length Describ
id int 11 主鍵
rolename varchar 255 角色名稱,全局唯一。shiro將通過角色名來進行鑒權

**Table:t_permission**

Name Type Length Describ
id int 11 主鍵
role_id int 11 關聯role的外鍵
dataDomain varchar 255 系統數據模型的域(自己定義的概念,下面我們將會介紹)
dataType varchar 255 permission對應的系統實例的類型
operation varchar 255 permession許可的操作,例如add,del等等

**Table:t_authc_map**

Name Type Length Describ
id int 11 主鍵
authcType varchar 255 驗證類型,枚舉:anon,authc,perms,roles
url varchar 255 系統資源的url
val varchar 255 具體的權限字符串,例如:user:query

t_user和t_role表就不用詳細介紹了,就是系統的用戶表和角色表。它與t_role角色表的關系是多對多的關系,即一個用戶可以有多個角色,一個角色可以包含多個用戶。

那么我們介紹一下t_permission表,這個表存放的數據是角色擁有的permission(這里我們就用shiro的permission概念,不翻譯了。因為翻譯過來是許可,但是許可二字還不能完全闡釋permission的概念)。每一個role會對應一個permission,即一對一的關系。

表t_authc_map存儲的是Shiro filter需要的配置數據,這些數據組合起來,定義了訪問控制(Access Controll)的規則,即定義了哪些url可以被擁有哪些permission或者擁有哪些role的用戶訪問。在我們這個例子中,其實這張表用處不大。當初設計這樣一張表的目的是,能夠動態管理訪問控制的規則,但是并不能。


提示: 訪問控制規則的數據是在Spring bean初始化時就加載給了訪問控制的filter。我們試想一下,在你的webapp運行時(runtime),我們可以通過一些手段來修改系統的訪問控制規則,那么勢必會造成用戶提交事務時的處理變得非常復雜。例如,用戶正在訪問一個url連接,我們通過后臺修改了url的訪問控制權限,這時這個用戶已經提交了一次事務操作,那么怎么判斷這次提交是否合法呢?要把這個問題處理清楚就很復雜。那么你可能會問,如果我為系統增加了一個模塊,模塊中有一些新建的url需要提供給用戶訪問,但是我不想重啟我的應用,直接在數據庫中配置完成,怎么辦?我想,既然增加了模塊,當然需要重新部署,那么僅通過配置數據完成部署,我感覺在現在Spring MVC下,很難實現。所以個人看法,訪問控制規則數據使用配置文件還是持久化到數據庫,沒有什么區別。但是本文中還是會介紹如何將訪問控制規則持久化到數據庫中。


shiroTest模塊

我們可以看見項目中有一個shiroTest模塊,這個模塊中主要實現在單元測試時,使用的通用程序。在本例中,我們在shiroTest模塊中實現一個proxool數據源,為其他模塊在單元測試時提供數據庫連接。

請注意,我們這里配置的數據源,僅提供給單元測試使用。而我們的webapp中將使用Spring 的JNDI數據源。為什么這么做呢?主要原因是:本例中我們使用的是Tomcat做為中間件,但是實際項目的生產環境,可能使用商業中間件,例如Weblogic等等。那么我們在遷移過程中,就不用考慮中間件使用的是什么數據源,只去調用中間件JNDI上綁定的數據源名稱就可以了。而且這些商業中間件一般都有很好的數據源管理功能。如果我們使用獨立的數據源,那么數據源就脫離的中間件的管理,豈不是功能浪費?

我們在test中,實現一個測試用例,這個測試用例主要測試數據源的連接:

1 2 3 4 5 6 7 8 public void testApp() throws SQLException { ????????ApplicationContext cxt = new ClassPathXmlApplicationContext( ????????????????"classpath*:conf/*-beans.xml"); ????????DataSource ds= (DataSource) cxt.getBean("ds-default"); ????????Connection con=ds.getConnection(); ????????con.close(); ????????assertTrue(true); }

我們在shiroTest項目根目錄下運行mvn test,測試一下。

base模塊

base模塊主要實現的是整個項目中,各個模塊公用的程序。其中包含了:

  • Hibernate Session Factory
  • Ehcache
  • POJO Class
  • BaseDao 所有dao的父類
  • Hibernte 事務管理

authmgr模塊

authmgr模塊實現了如下功能

  • 登錄
  • 登出
  • 查詢訪問控制規則數據
  • 實現自定義Realm
  • 實現Shiro的SecurityManager

authmgr模塊業務接口

我們來看一下接口com.ultimatech.shirodemo.authmgr.service.IAuthService

*com.ultimatech.shirodemo.authmgr.service.IAuthService*

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public interface IAuthService { ????/** ?????* 用戶登錄接口 ?????* @param userName 登錄用戶名 ?????* @param password 密碼 ?????* @throws AuthenticationException ?????*/ ????void logIn(String userName, String password) throws AuthenticationException; ????/** ?????* 用戶登出系統 ?????*/ ????void logOut(); ????/** ?????* 獲得數據庫中存儲的訪問控制數據 ?????* @return ?????*/ ????List<AuthcMap> getFilterChainDefinitions(); }

自定義實現Realm

我們來看一下我們的Realm是如何實現:

*com.ultimatech.shirodemo.authmgr.realm.MyRealm*

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 ...... @Component("myRealm") public class MyRealm extends AuthorizingRealm { ????@Autowired ????public MyRealm(@Qualifier("shiroEncacheManager") CacheManager cacheManager) { ????????super(cacheManager); ????} ????@Autowired ????private IAuthDao dao; ???...... ????@Override ????protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { ????????//獲取登錄時輸入的用戶名 ????????String loginName = (String) principalCollection.fromRealm(getName()).iterator().next(); ????????//到數據庫查是否有此對象 ????????User user = this.getDao().findByName(loginName); ????????if (user != null) { ????????????//權限信息對象info,用來存放查出的用戶的所有的角色(role)及權限(permission) ????????????SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); ????????????//用戶的角色集合 ????????????info.setRoles(user.getRolesName()); ????????????//用戶的角色對應的所有權限,如果只使用角色定義訪問權限,下面的四行可以不要 ????????????List<Role> roleList = user.getRoleList(); ????????????for (Role role : roleList) { ????????????????info.addStringPermissions(role.getPermissionsString()); ????????????} ????????????return info; ????????} ????????return null; ????} ????@Override ????protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { ????????//UsernamePasswordToken對象用來存放提交的登錄信息 ????????UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; ????????//查出是否有此用戶 ????????User user = this.getDao().findByName(token.getUsername()); ????????if (user != null) { ????????????//若存在,將此用戶存放到登錄認證info中 ????????????return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName()); ????????} ????????return null; ????} }

Shiro的SecurityManager

我們在Spring 容器中聲明一個名叫securityManager的bean。在resources/conf/authmgr-beans.xml中,我們看見如下代碼:

1 2 3 4 5 6 7 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> ????<!-- ref對應我們寫的realm? myRealm --> ????<property name="realm" ref="myRealm"/> ????<!-- 使用下面配置的緩存管理器 --> ????<property name="cacheManager" ref="shiroEncacheManager"/> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

由于我們很多模塊都會用到共享緩存,所以以上<property name="cacheManager" ref="shiroEncacheManager"/>中的shiroEncacheManager被定義在base模塊中。

我們可以去base模塊的目錄下找到resources/conf/base-beans.xml,找到如下代碼:

1 2 3 4 5 6 7 8 <bean id="shiroEncacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> ????<property name="cacheManager" ref="ehCacheManager"/> </bean> <bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> ????<property name="configLocation" value="classpath:ehcache.xml"></property> ????<property name="shared" value="true"/> </bean>

shiroWebapp模塊

shiroWebapp模塊是本例中的web應用。主要集成了Spring MVC框架、Hibernate框架,以及我們的安全框架Apache Shiro。

我們使用Shiro Filter來進行訪問控制,那么在web.xml文件中進行了如下配置:

1 2 3 4 5 6 7 8 <filter> ????<filter-name>shiroFilter</filter-name> ????<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> ????<filter-name>shiroFilter</filter-name> ????<url-pattern>/*</url-pattern> </filter-mapping>

我們使用Spring的DelegatingFilterProxy來創建Shiro Filter。<filter-name>shiroFilter</filter-name>這個參數要與Spring中Shiro Filter Bean的名字保持一致。在shiroWebapp下的resources/conf下的web-beans.xml文件中,我們可以看見Shiro Filter的配置:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <bean id="filterChainDefinitions" class="com.ultimatech.shirodemo.web.filter.ShiroFilterChainDefinitions"> ????<property name="filterChainDefinitions"> ????????<value> ????????????/html/**=anon ????????????/js/**=anon ????????????/css/**=anon ????????????/images/**=anon ????????????/authc/login=anon ????????????/login=anon ????????????<!--/user=perms[user:del]--> ????????????/user/add=roles[manager] ????????????/user/del/**=roles[admin] ????????????/user/edit/**=roles[manager] ????????????<!--/** = authc--> ????????</value> ????</property> </bean> <!-- 配置shiro的過濾器工廠類,id- shiroFilter要和我們在web.xml中配置的過濾器一致 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> ????<!-- 調用我們配置的權限管理器 --> ????<property name="securityManager" ref="securityManager"/> ????<!-- 配置我們的登錄請求地址 --> ????<property name="loginUrl" value="/"/> ????<!-- 配置我們在登錄頁登錄成功后的跳轉地址,如果你訪問的是非/login地址,則跳到您訪問的地址 --> ????<property name="successUrl" value="/user"/> ????<!-- 如果您請求的資源不再您的權限范圍,則跳轉到/403請求地址 --> ????<property name="unauthorizedUrl" value="/html/403.html"/> ????<!-- 權限配置 --> ????<property name="filterChainDefinitionMap" ref="filterChainDefinitions" /> </bean>

訪問控制數據

我們看見上面的filterChainDefinitions中,我們自定義了一個FacotryBean,這個bean主要實現將配置文件中的訪問控制數據和數據庫中的訪問控制數據整合在一起。(雖然我們之前已經說了,這兩種方式沒什么區別。)

*com.ultimatech.shirodemo.web.filter.ShiroFilterChainDefinitions*

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class ShiroFilterChainDefinitions implements FactoryBean<Ini.Section> { ????@Autowired ????private IAuthService authService; ????...... ????public static final String PREMISSION_STRING = "perms[{0}]"; ????public static final String ROLE_STRING = "roles[{0}]"; ????public Ini.Section getObject() throws Exception { ????????List<AuthcMap> list = this.getAuthService().getFilterChainDefinitions(); ????????Ini ini = new Ini(); ????????ini.load(this.getFilterChainDefinitions()); ????????Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME); ????????for (AuthcMap map : list) { ????????????String s = null; ????????????switch (AuthcType.valueOf(map.getAuthcType())) { ????????????????case roles: ????????????????????s = MessageFormat.format(ROLE_STRING, map.getVal()); ????????????????????break; ????????????????case perms: ????????????????????s = MessageFormat.format(PREMISSION_STRING, map.getVal()); ????????????????????break; ????????????????case authc: ????????????????????s = AuthcType.authc.name(); ????????????????case anon: ????????????????????s = AuthcType.anon.name(); ????????????????default: ????????????????????s = AuthcType.authc.name(); ????????????} ????????????section.put(map.getUrl(), s); ????????} ????????return section; ????} ???...... }

關于訪問控制數據,我們要注意Shiro Filter在執行訪問控制時,是按訪問控制數據的順序來逐個驗證的,而我們將數據庫中的訪問控制數據追加到配置文件的后面。例如上面的配置:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <bean id="filterChainDefinitions" class="com.ultimatech.shirodemo.web.filter.ShiroFilterChainDefinitions"> ????<property name="filterChainDefinitions"> ????????<value> ????????????/html/**=anon ????????????/js/**=anon ????????????/css/**=anon ????????????/images/**=anon ????????????/authc/login=anon ????????????/login=anon ????????????/user/add=roles[manager] ????????????/user/del/**=roles[admin] ????????????/user/edit/**=roles[manager] ????????</value> ????</property> </bean>

追加上我們在數據庫中的訪問配置數據:

id authcType url val
1 perms /user user:query
2 authc /** ?

那么全部訪問控制數據應該是:

1 2 3 4 5 6 7 8 9 10 11 /html/**=anon /js/**=anon /css/**=anon /images/**=anon /authc/login=anon /login=anon /user/add=roles[manager] /user/del/**=roles[admin] /user/edit/**=roles[manager] /user=perms[user:query] /**=authc

這里我們要強調一下,如果把基于角色和基于permission的控制放在/**=authc之后的控制是不會起作用的。例如:

1 2 3 4 5 6 7 8 9 10 11 /html/**=anon /js/**=anon /css/**=anon /images/**=anon /authc/login=anon /login=anon /user/add=roles[manager] /user/del/**=roles[admin] /user/edit/**=roles[manager] /**=authc /user=perms[user:query]

這時如果用戶rose擁有user:del的permission,在他登錄系統以后也是可以訪問/user路徑的。其實我們想實現只有擁有user:query的用戶才能訪問/user,而rose擁有的是user:del。我們設置了/user=perms[user:query],而rose并沒有user:query這樣的permission,為什么rose還能訪問/user呢?這是因為,Shior Filter先使用訪問控制規則/**=authc對rose的權限進行了驗證,那么rose是一個已知身份的用戶,所以他可以訪問所有url,除了/**=authc之前設置的規則限制不能訪問的url。

是不是很混亂,一部分訪問控制規則在配置文件中,一部分又在數據庫中,而且訪問控制還有順序要求,一旦我們忽略任意一部分訪問控制數據,我們的設置就很難達到我們預期的效果。所以,將訪問控制數據分開并不是一個好的實踐。

我們這里實現了使用數據庫配置訪問控制數據,僅僅是為了開闊一下思路,并不推薦同時使用數據庫配置和配置文件配置。

關于permission語法

我們可以參考Understanding Permissions in Apache Shiro。你可能會發現好長的一篇文章啊!

那么下面我就我個人的理解,簡單對permission語法說明一下。

在我們設計系統時,我們經過一系列的分析過程,會得到我們要實現的系統中存在哪些實體。例如,系統中存在用戶(user),工作流(workflow)等實體。我們對這些實體進行抽象化,構成我們系統的基礎模型。那么實體除了數據屬性,例如,用戶名(username),流程名稱(flowname)等,還具備一些功能(function)或者叫做方法(method)的特征。我們使用OOP的思想來設計系統,那么我們抽象出來的實體就是我們所說的實體類,這些實體類代表了很多實體對象,例如,user類中,實際包含了tom,jack和rose,這些用戶的一個子集就組成了一個數據域。那么我們的permission就是由系統實體和功能,以及一個數據域組成,格式就像這樣:實體:功能:數據域。

例如: perms[user:query:*]——表示允許查詢(query)用戶(user實體類)所有(*)對象的許可。 perms[user:query,add,del,update]——表示允許查詢(query)、添加(add)、刪除(del)和更新(update)用戶(user)所有對象的許可。 perms[user:query:jack,rose]——表示允許查詢(query)用戶(user)中jack和rose數據的許可。 perms[workflow:approve:order]——表示允許操作工作流程(workflow)中一個名叫order的流程的審批許可。

試驗

我們掌握了項目中集成Apache Shiro的方法后,將項目在IDEA中run或者debug起來。使用tom、jack和rose用戶登錄系統中,看看會有什么現象。當然用戶、角色和permission數據都在db.sql文件中,導入數據庫時已經一起導入了。你可以修改這些數據,以及他們之間的關系來體驗Shiro的安全框架。

總結

希望通過這個說明,能夠讓你了解在本項目中是如何集成Apache Shiro安全框架的。

在接下來的計劃中,我們將實現在集群環境中使用Apache Shiro。


原文出處:?holynull

from:?http://www.importnew.com/22908.html

總結

以上是生活随笔為你收集整理的在Spring MVC中使用Apache Shiro安全框架的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲福利电影网 | free黑人多人性派对hd | 好吊一区二区三区 | 天天干天天干天天干 | 自拍偷拍精品视频 | 国产在线精品福利 | 男女激情在线观看 | 成人免费91 | 99精品在线播放 | 精品一区二三区 | 日本激情一区二区 | 欧美乱淫| 亚洲免费视频网 | 国产日韩av一区二区 | 校园春色综合 | 狠狠狠狠狠狠狠 | 日韩av高清 | 大桥未久av一区二区三区中文 | 国产在线97 | 西西4444www大胆无视频 | 成人激情开心 | 精品啪啪 | 日韩免费视频一区 | 午夜资源站 | 欧美高清视频在线观看 | 美女网站免费观看视频 | 人人插人人看 | 夜夜爽夜夜叫夜夜高潮漏水 | 黄色片网站大全 | 日韩免费av一区二区 | 超碰国产一区二区三区 | 欧美日韩一区二区视频观看 | 一区二区三区麻豆 | 久视频在线观看 | 色妞色视频一区二区三区四区 | 欲色影音 | 欧美国产一二三区 | 国产乡下妇女三片 | 永久毛片 | 女人喂男人奶水做爰视频 | 亚洲精品无amm毛片 国内一区二区三区 | 黄色精品在线 | 国产一卡二卡三卡四卡 | 国产原创麻豆 | 久久99免费视频 | 男女啪啪毛片 | 国产精品成人一区 | 日本精品在线观看视频 | 被黑人猛躁10次高潮视频 | 哪里可以免费看av | 久草欧美 | 午夜视频在线观看一区 | 3d动漫精品啪啪一区二区免费 | 在线a网站| 一区二区三区视频在线观看免费 | 亚洲美女屁股眼交8 | 影音先锋中文字幕在线视频 | 成人午夜电影网站 | 91插插影库 | 久久少妇视频 | 无码精品人妻一区二区 | 免费性视频 | 亚洲欧美在线看 | 九色91视频 | 免费的黄色网址 | free女性xx性老大太 | 国产精品久久久不卡 | xxxx日本免费| 欧美字幕| 欧美日韩一二三 | 久久久麻豆 | 日韩全黄 | 成人片在线看 | 日本中文在线观看 | 四虎8848精品成人免费网站 | 日韩欧洲亚洲AV无码精品 | av中文字幕一区 | 精品久久免费视频 | 中文字幕一区电影 | 99国产精品久久久久 | 国产精品精| 红桃视频一区二区三区免费 | 国产黑人 | 伦理黄色片 | 欧美综合激情网 | 深夜视频在线看 | 日日夜夜超碰 | 足疗店女技师按摩毛片 | 成人在线观看网址 | www.亚洲在线| 国产精品美女毛片真酒店 | 亚洲精品乱码久久久久久麻豆不卡 | 日本三级视频网站 | 午夜精品999 | 中文字幕成人在线 | 一二三四区在线 | 超碰丝袜 | 秋霞黄色片 | 亚洲一区久久 |