前面簡(jiǎn)單介紹了shiro這個(gè)框架的一些基本知識(shí),包括其架構(gòu)模型,主要的功能,關(guān)鍵名稱(chēng)的含義,以及核心模塊和對(duì)應(yīng)的接口定義。
開(kāi)始的話(huà)
今天我們從一個(gè)簡(jiǎn)單示例,先了解使用shiro實(shí)現(xiàn)Web應(yīng)用認(rèn)證時(shí),一名開(kāi)發(fā)者需要做些什么。同樣秉持著技術(shù)學(xué)習(xí)的原則,我們僅僅使用shiro框架以及一些其他簡(jiǎn)化開(kāi)發(fā)的工具庫(kù),不會(huì)涉及到一些IOC容器,這樣在進(jìn)行模塊配置以及依賴(lài)關(guān)系梳理時(shí),通過(guò)手動(dòng)的配置的方式,讓我們更加容易理解...
文章介紹
通過(guò)這篇文章,你可以有以下幾個(gè)方面的收獲:
- 基于maven創(chuàng)建一個(gè)項(xiàng)目,養(yǎng)成項(xiàng)目依賴(lài)統(tǒng)一管理的習(xí)慣
- 了解shiro在項(xiàng)目中的使用過(guò)程以及相關(guān)的配置
- 了解如何實(shí)現(xiàn)通過(guò)shiro完成認(rèn)證以及授權(quán)
- 了解shiro認(rèn)證流程
- 對(duì)shiro從理論的認(rèn)識(shí)升華到基礎(chǔ)實(shí)踐
- 獲得一個(gè)演示示例
示例實(shí)現(xiàn)
創(chuàng)建項(xiàng)目
1) 你可以選擇通過(guò)你的IDE快速創(chuàng)建一個(gè)項(xiàng)目,比如通過(guò)Intellij Idea,通過(guò)File->New->Project選擇Maven Archetype創(chuàng)建一個(gè)空項(xiàng)目,這里archetype可以選擇quickstart

這里你很可能遇到一個(gè)idea的bug,按上圖提交后,發(fā)現(xiàn)idea卡死了,項(xiàng)目創(chuàng)建失敗且無(wú)法打開(kāi),如果沒(méi)有就恭喜你了
2)最終我們會(huì)得到一個(gè)文件夾,里面包含一個(gè)pom.xml文件,結(jié)構(gòu)如下(如果有其他的內(nèi)容建議刪除,比如src,因?yàn)檫@個(gè)pom我們作為項(xiàng)目parent維護(hù))

添加依賴(lài)
細(xì)心的你會(huì)注意到,在根目錄下有個(gè)pom.xml,同時(shí)還有個(gè)ui-mvc目錄下也有個(gè)pom.xml文件,根目錄下的我一般習(xí)慣作為整個(gè)項(xiàng)目的父級(jí)依賴(lài)配置文件,用來(lái)管理所有依賴(lài)、插件版本以及屬性值,ui-mvc下的pom主要通過(guò)parent實(shí)現(xiàn)屬性繼承,這樣來(lái)實(shí)現(xiàn)配置集中化管理
./pom.xml
< project >
//...
< groupId >com.sucls.security< /groupId >
< artifactId >auth-shiro< /artifactId >
< version >1.0-SNAPSHOT< /version >
< packaging >pom< /packaging >
< properties >
< project.build.sourceEncoding >UTF-8< /project.build.sourceEncoding >
< maven.compiler.source >1.8< /maven.compiler.source >
< maven.compiler.target >1.8< /maven.compiler.target >
< shiro.version >1.9.1< /shiro.version >
// ...
< /properties >
< dependencyManagement >
< dependencies >
< !-- 核心 -- >
< dependency >
< groupId >org.apache.shiro< /groupId >
< artifactId >shiro-core< /artifactId >
< version >${shiro.version}< /version >
< /dependency >
< dependency >
< groupId >org.apache.shiro< /groupId >
< artifactId >shiro-web< /artifactId >
< version >${shiro.version}< /version >
< /dependency >
// ...
< /dependencies >
< /dependencyManagement >
// ...
< /project >
./ui-mvc/pom.xml
< parent >
< groupId >com.sucls.security< /groupId >
< artifactId >auth-shiro< /artifactId >
< version >1.0-SNAPSHOT< /version >
< relativePath >../../pom.xml< /relativePath >
< /parent >
< artifactId >auth-shiro-ui-mvc< /artifactId >
< packaging >war< /packaging >
< name >ui-mvc< /name >
< dependencies >
< !-- 核心 -- >
< dependency >
< groupId >org.apache.shiro< /groupId >
< artifactId >shiro-core< /artifactId >
< /dependency >
< dependency >
< groupId >org.apache.shiro< /groupId >
< artifactId >shiro-web< /artifactId >
< /dependency >
< /dependencies >
大部分內(nèi)容都省略了,可以參考文末源代碼,主要引入了shiro相關(guān)的依賴(lài),以及一個(gè)提高開(kāi)發(fā)效率的工具包
編寫(xiě)shiro相關(guān)配置
我們所有代碼都會(huì)寫(xiě)到ui-mvc模塊下,看到名稱(chēng)就知道我們通過(guò)mvc的結(jié)構(gòu),因此前端是通過(guò)jsp這個(gè)老技術(shù),后面會(huì)講到如何通過(guò)前后端分離來(lái)實(shí)現(xiàn)認(rèn)證功能。
下面主要從以下幾個(gè)方面進(jìn)行配置:
web.xml以前說(shuō)過(guò),認(rèn)證基本都是基于Filter實(shí)現(xiàn),同樣shiro有一個(gè)核心的過(guò)濾器(該過(guò)濾器會(huì)將我們的配置解析成一個(gè)個(gè)過(guò)濾器鏈)
< filter >
< filter-name >shiroFilter< /filter-name >
< filter-class >org.apache.shiro.web.servlet.ShiroFilter< /filter-class >
< /filter >
< filter-mapping >
< filter-name >shiroFilter< /filter-name >
< url-pattern >/*< /url-pattern >
< /filter-mapping >
配置監(jiān)聽(tīng),在系統(tǒng)啟動(dòng)時(shí)基于ServletContextListener調(diào)用初始化參數(shù)完成一些基本的系統(tǒng)初始化工作
< context-param >
< param-name >shiroEnvironmentClass< /param-name >
< param-value >org.apache.shiro.web.env.DefaultWebEnvironment< /param-value >
< /context-param >
< listener >
< listener-class >com.sucls.security.security.SimpleEnvironmentLoaderListener< /listener-class >
< /listener >
這里通過(guò)自定義的監(jiān)聽(tīng),SimpleEnvironmentLoaderListener類(lèi)承載了shiro基本上所有的配置,在這里我們會(huì)完整地構(gòu)建SecurityManager對(duì)象以及Filter的配置,如果讀過(guò)以前的文章你就會(huì)知道,SecurityManager主要的工作包括:
- 代理實(shí)現(xiàn)用戶(hù)身份的認(rèn)證
- 對(duì)API結(jié)果進(jìn)行緩存
- 實(shí)現(xiàn)了用戶(hù)多種形式登錄(多Realm)
- 實(shí)現(xiàn)用戶(hù)會(huì)話(huà)管理
- 實(shí)現(xiàn)記住我功能
- ...
ShiroFilter配置
FormAuthenticationFilter authcFilter = (FormAuthenticationFilter) filterChainResolver.getFilterChainManager().getFilters().get(DefaultFilter.authc.name());
authcFilter.setLoginUrl("/login.jsp");
authcFilter.setSuccessUrl("/index.html");
filterChainResolver.getFilterChainManager().addToChain("/webjars/**", DefaultFilter.anon.name());
filterChainResolver.getFilterChainManager().addToChain("/assets/**", DefaultFilter.anon.name());
filterChainResolver.getFilterChainManager().addToChain("/**", DefaultFilter.authc.name());
這里主要通過(guò)配置FilterChainResolver對(duì)象來(lái)完成ShiroFilter對(duì)象的構(gòu)建,后面講到源代碼時(shí)會(huì)細(xì)說(shuō)。
SecurityManager配置
private void configureWebSecurityManager(DefaultWebSecurityManager securityManager) {
//
securityManager.setAuthenticator(newAuthenticator());
securityManager.setRealms(Arrays.asList(initRealm()));
}
private Authenticator newAuthenticator() {
ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy()); // 至少一個(gè)Realm
authenticator.setRealms(Arrays.asList(initRealm()) );
return authenticator;
}
private Realm initRealm(){
return RealmBuilder.create()
.inMemoryRealm() .user("admin").password("123456").role("ROLE_ADMIN").permissions(Arrays.asList("read","edit","create","delete"))
.and()
.user("user").password("123456").role("ROLE_USER").permission("read")
.build();
}
這里僅根據(jù)需要配置了Realm以及認(rèn)證規(guī)則Authenticator
引入頁(yè)面
前端模板來(lái)源bootstrap quick,在此基礎(chǔ)上修改了遠(yuǎn)程資源(js、css)為本地引用,以及引入jsp文件頭對(duì)應(yīng)的配置
啟動(dòng)項(xiàng)目
通過(guò)引入tomcat插件來(lái)啟動(dòng)項(xiàng)目:
< plugin >
< groupId >org.apache.tomcat.maven< /groupId >
< artifactId >tomcat7-maven-plugin< /artifactId >
< version >2.2< /version >
< configuration >
< port >8080< /port >
< path >/< /path >
< /configuration >
< /plugin >
這樣不需要我們單獨(dú)弄個(gè)tomcat,通過(guò)插件即可實(shí)現(xiàn)項(xiàng)目熱啟動(dòng),方便調(diào)試與靜態(tài)頁(yè)面的修改

執(zhí)行認(rèn)證
1)進(jìn)入系統(tǒng) http://localhost:8080/ 由于沒(méi)有登錄,跳轉(zhuǎn)到登錄頁(yè)http://localhost:8080/login.jsp

2)輸入用戶(hù)名密碼,按以上的配置admin/123456,登錄成功,進(jìn)入主頁(yè)

3)用戶(hù)鑒權(quán),上面可以看到admin配置了ROLE_ADMIN角色,user配置了ROLE_USER角色,所以
admin登錄時(shí):
訪(fǎng)問(wèn) http://localhost:8080/system/getProperties.json 正常返回?cái)?shù)據(jù) ;
訪(fǎng)問(wèn) http://localhost:8080/subject/getSubject.json 進(jìn)入未授權(quán)頁(yè)面
關(guān)于shiro鑒權(quán)部分主要是基于Filter以及AOP完成,其中請(qǐng)求交易基于Filter,在請(qǐng)求時(shí)基于登錄權(quán)限信息進(jìn)行交易攔截,而AOP則可以針對(duì)方法的調(diào)用階段,更加靈活和通用。具體的實(shí)現(xiàn)過(guò)程后面會(huì)細(xì)說(shuō),同時(shí)可以看到示例簡(jiǎn)單的實(shí)現(xiàn)過(guò)程
示例分析
在整個(gè)示例中,回憶我們做了什么,有什么用?
- 引入shiro相關(guān)的依賴(lài)包,這點(diǎn)沒(méi)什么說(shuō)的
- 配置web.xml的Filter以及Listener Listener則是基于Servlet的ServletContextListener規(guī)則,在web容器啟動(dòng)后,調(diào)用contextInitialized方法完成容器初始化工作。這里的初始化包括:
- 對(duì)SecurityManager的配置,后面我們會(huì)看到關(guān)于shiro的配置基本都是針對(duì)這個(gè)對(duì)象。包括Realm、多Realm認(rèn)證策略、RememberMe、SessionManager等等
- 對(duì)FilterChainResolver的配置,目的是為了完善ShiroFilter對(duì)象,主要針對(duì)請(qǐng)求路徑對(duì)應(yīng)的過(guò)濾器,下面每一行都是一個(gè)根據(jù)請(qǐng)求路徑匹配的過(guò)濾器鏈,一段請(qǐng)求匹配,則進(jìn)入對(duì)應(yīng)過(guò)濾器鏈,所有注意配置順序
/assets/** = anon
/login = authc
/admin/** = roles[ROLE_ADMIN]
/admin/add* = perms[add:*] //[action:type:instance]
/** = authc
- 引入靜態(tài)頁(yè)面,這里基于jsp實(shí)現(xiàn),當(dāng)然還有其他前端模板引擎可以使用,其中靜態(tài)資源通過(guò)引入webjars來(lái)加載
- 由于沒(méi)有引入springmvc,在資源映射(請(qǐng)求到頁(yè)面或交易)以及依賴(lài)管理、AOP裝配等等都是手動(dòng)通過(guò)代碼完成,增加了代碼復(fù)雜度,但是結(jié)構(gòu)會(huì)更清晰,更容易理解
要知道,我們的目的是為SecurityManager注入屬性以及配置ShiroFilter過(guò)濾規(guī)則,并不一定需要基于ServletContextListener,這只是一個(gè)選擇,比如還可以在Filter的init方法中完成,只要保證系統(tǒng)啟動(dòng)后對(duì)應(yīng)的配置加載或處理完成即可。
-
模塊
+關(guān)注
關(guān)注
7文章
2837瀏覽量
53282 -
接口
+關(guān)注
關(guān)注
33文章
9519瀏覽量
157015 -
容器
+關(guān)注
關(guān)注
0文章
531瀏覽量
22965 -
Web應(yīng)用
+關(guān)注
關(guān)注
0文章
16瀏覽量
3683
發(fā)布評(píng)論請(qǐng)先 登錄
uClinux下動(dòng)態(tài)Web技術(shù)的實(shí)現(xiàn)方法
基于網(wǎng)格環(huán)境實(shí)現(xiàn)WEB應(yīng)用編程研究
uClinux下動(dòng)態(tài)Web技術(shù)的實(shí)現(xiàn)方法
基于Linux的WEB服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn)
HTTP認(rèn)證及其在Web平臺(tái)中的實(shí)現(xiàn)
基于Web的智能答疑系統(tǒng)的設(shè)計(jì)和實(shí)現(xiàn)劉江平
shiro簡(jiǎn)單教程,環(huán)境搭建,權(quán)限控制,登陸驗(yàn)證
Apache Shiro框架的詳細(xì)資料說(shuō)明
如何一鍵實(shí)現(xiàn)openWRT的web認(rèn)證功能
使用RESTful Web服務(wù)的過(guò)程
shiro綜合利用工具介紹
再見(jiàn)了shiro
Shiro功能介紹
基于Web的遠(yuǎn)程監(jiān)控系統(tǒng)設(shè)計(jì)及實(shí)現(xiàn)
shiro如何實(shí)現(xiàn)Web應(yīng)用認(rèn)證
評(píng)論