下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第1章一個簡單的HelloWorldSpringSecurity中可以使用Acegi-1.x時代的普通配置方式,也可以使用從2.0時代オ出現(xiàn)的命名空間配置方式,實(shí)際上這兩者實(shí)現(xiàn)的功能是完全一致的,只是新的命名空間配置方式可以把原來需要幾百行的配置壓縮成短短的幾十行。我們的教程中都會使用命名空間的方式進(jìn)行配置,凡事務(wù)求最簡。1.1.配置過濾器為了在項(xiàng)目中使用SpringSecurity控制權(quán)限,首先要在web.xml中配置過濾器,這樣我們就可以控制對這個項(xiàng)目的每個請求了。<filter><filter-name>springSecurityFilterChain</filter-name)<fi1ter-class>org.springframework.web.filter.De1egatingFi11erProxy</filter-class></filter><fi1ter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></filter-mapping>所有的用戶在訪問項(xiàng)目之前,都要先通過SpringSecurity的檢測,這從第一時間把沒有授權(quán)的請求排除在系統(tǒng)之外,保證系統(tǒng)資源的安全。關(guān)于過濾器配置的更多講解可以參考/tutorial/jsp/html/jsp-ch-07.html#jsp-ch-Q7-03-0lo使用命名空間在applicationContext.xml中使用SpringSecurity提供的命名空間進(jìn)行配置。<?xmlversion="1.0〃encoding二〃UTF-8〃?><beans:beansxmlns=z,/schema/securityz,Oxmlns:beans=,,http://www.springframework,org/schema/beansxmlns:xsi=,z/2001/XMLSchema-instancexsi:schemaLocation=z//schema/beans/schema/beans/spring-beans-2.0.xsd/schema/security
/schema/security/spring-security_2.0.4.xsd"〉<httpauto-config='true'>?<intercept-urlpattern="/admin.jsp"access="ROLE_ADMIN”/〉?<intercept-urlpattern-/**"access="ROLE_USER"/></http><authentication-provider><user-service><username="admin"password=*admin"authorities=,,ROLE_USER,ROLE_ADMIN"ハ?<username="user"password="user"authorities="ROLE_USER”/>く/user-service></authentication-provider></beans:beans>?聲明在xml中使用SpringSecurity提供的命名空間。?http部分配置如何攔截用戶請求。auto-config='true’將自動配置兒種常用的權(quán)限控制機(jī)制,包括form,anonymous,rememberMe。?我們利用intercept-url來判斷用戶需要具有何種權(quán)限才能訪問對應(yīng)的url資源,可以在pattern中指定一個特定的url資源,也可以使用通配符指定ー組類似的url資源。例子中定義的兩個intercepter-url,第一個用來控制對/admin,jsp的訪問,第二個使用了通配符/**,說明它將控制對系統(tǒng)中所有url資源的訪問。在實(shí)際使用中,SpringSecurity采用的是ー種就近原則,就是說當(dāng)用戶訪問的url資源滿足多個intercepter-ur!時,系統(tǒng)將使用第一?個符合條件的intercept-url進(jìn)行權(quán)限控制。在我們這個例子中就是,當(dāng)用戶訪問/admin,jsp時,雖然兩個intercept-url都滿足要求,但因?yàn)榈谝籢intercept-url排在上面,所以SpringSecurity會使用第一個intercept-url中的配置處理對/admin.jsp的請求,也就是說,只有那些擁有了ROLE_ADMIN權(quán)限的用戶才能訪問/admin.jspoaccess指定的權(quán)限部分比較有趣,大家可以注意到這些權(quán)限標(biāo)示符都是以ROLE_開頭的,實(shí)際上這與SpringSecurity中的Voter機(jī)制有著千絲萬縷的聯(lián)索,只有包含了特定前綴的字符串オ會被SpringSecurity處理。目前來說我們只需要記住這一點(diǎn)就可以了,在教程以后的部分中我們會詳細(xì)講解Voter的內(nèi)容。0user-service中定義了兩個用戶,admin和user。為了簡便起見,我們使用明文定義了兩個用戶對應(yīng)的密碼,這只是為了當(dāng)前演示的方便,之后的例子中我們會使用SpringSecurity提供的加密方式,避免用戶密碼被他人竊取。最最重要的部分是authorities,這里定義了這個用戶登陸之后將會擁有的權(quán)限,它與上面intercept-ur!中定義的權(quán)限內(nèi)容ーー對應(yīng)。每個用戶可以同時擁有多個權(quán)限,例子中的admin用戶就擁有ROLE_ADMIN和ROLE_USER兩種權(quán)限,這使得admin用戶在登陸之后可以訪問ROLE_ADMIN和ROLE_USER允許訪問的所有資源。與之對應(yīng)的是,user用戶就只擁有ROLE_USER權(quán)限,所以他只能訪問ROLEUSER允許訪問的資源,而不能訪問ROLEADMIN允許訪問的資源。完善整個項(xiàng)目因?yàn)镾pringSecurity是建立在Spring的基礎(chǔ)之上的,所以web.xml中除了需要配置我們剛剛提到的過濾器,還要加上加載Spring的相關(guān)配置。最終得到的web.xml看起來像是這樣:<?xmlversion="1.0〃encoding二〃UTF-8”?><web-appversion二"2.4"xmlns二"http:〃/xml/ns/j2ee"xmlns:xsi二/2001/XMLSchema-instancexsi:schemaLocation=///xml/ns/j2ee/xml/ns/j2ee/web_app_2_4.xsd"><context-param>くparam-name>contextConfigLocationく/param-name)<param-value>classpath:applicationContext*.xmlく/param-value〉</context-param><filter><filter-name>springSecurityFilterChain</filter-name>くfilter-class〉org.springframework,web.filter.De1egatingFi1terProxy</filter-class〉</filter><fi1ter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></filter-mapping〉<listener>
<1istener-class>org.springframework.web.context.ContextLoaderListenerく/listener-class)</listener></web-app>演示不同權(quán)限的用戶登陸之后可以訪問不同的資源,我們?yōu)轫?xiàng)目添加了兩個jsp文件,admin,jsp和index.jspo其中admin,jsp只有那些擁有ROLE_ADMIN權(quán)限的用戶才能訪問,而index,jsp只允許那些擁有R0LEJSER權(quán)限的用戸才能訪問。最終我們的整個項(xiàng)目會變成下面這樣:+chOOl/+src/+main/+resources/*applicationContext.xml+webapp/+WEB-INF/web.xmladmin,jspindex,jsp+test/+resources/*pom.xml1.4.運(yùn)行示例首先確保自己安裝了Maven2。如果之前沒用過Maven2,可以參考我們的Maven2教程httj):///oa/maven2/html/index.html〇安裝好Maven2之后,進(jìn)入chOOl目錄,然后執(zhí)行mvn。信息:RootWebApplicationContext:initializationcompletedin1578ms2009-05-2811:37:50.171::INF0:StartedSe1ectChanne1Connector@:8080[INFO]StartedJettyServer[INFO]Startingscanneratintervalof10seconds.
等到項(xiàng)目啟動完成后。打開瀏覽器訪問http:〃localhost:8080/chOOl/就可以看到登陸頁面。LoginwithUsernameandPasswordUser:Password:|「 Remembermeonthiscomputer.提交查詢I重置圖1.1.用戶登陸這個簡陋的頁面是SpringSecurity自動生成的,一來為了演示的方便,二來避免用戶自己編寫登陸頁面時犯錯,SpringSecurity為了避免可能出現(xiàn)的風(fēng)險(xiǎn),連測試用的登錄頁面都自動生成出來了。在這里我們就省去編寫登陸頁面的步驟,直接使用默認(rèn)生成的登錄頁面進(jìn)行演示吧。首先讓我們輸入ー個錯誤用的用戶名或密碼,這里我們使用test/test,當(dāng)然這個用戶是不存在的,點(diǎn)擊提交之后我們會得到這樣ー個登陸錯誤提示頁面。Yourloginattemptwasnotsuccessful,tryagain.Reason:BadcredentialsLoginwithUsernameandPasswordUser: |testPassword:|I Remembermeonthiscomputer.提交查詢I重置圖1.2,登陸失敗如果輸入的是正確的用戶名和密碼,比如userVuser,系統(tǒng)在登陸成功后會默認(rèn)跳轉(zhuǎn)到index.jspousername:user
adminjsplogout圖1.3.登陸成功這時我們可以點(diǎn)擊admin.jsp鏈接訪問admin,jsp,也可以點(diǎn)擊logout進(jìn)行注銷。如果點(diǎn)擊了logout,系統(tǒng)會注銷當(dāng)前登陸的用戶,然后跳轉(zhuǎn)至登陸頁面。如果點(diǎn)擊了admin,jsp鏈接就會顯示如下頁面。HTTPERROR403Problemaccessing/helloworld/admin.jsp.Reason:AccessisdeniedPoweredbyJetty://圖1.4.拒絕訪問很遺憾,user用戶是無法訪問/admin.jsp這個url資源的,這在上面的配置文件中已經(jīng)有過深入的討論。我們在這里再簡要重復(fù)一遍:user用戶擁有ROLEJJSER權(quán)限,但是/admin,jsp資源需要用戶擁有ROLE_ADMIN權(quán)限才能訪問,所以當(dāng)user用戶視圖訪問被保護(hù)的/admin.jsp時,SpringSecurity會在中途攔截這ー請求,返回拒絕訪問頁面。為了正常訪問admin.jsp,我們需要先點(diǎn)擊logout注銷當(dāng)前用戶,然后使用admin/admin登陸系統(tǒng),然后再次點(diǎn)擊admin.jsp鏈接就會顯示出admin,jsp中的內(nèi)容。admin.jsp圖1.5.顯不admin,jsp根據(jù)我們之前的配置,admin用戶擁有ROLEJWMIN和ROLEJSER兩個權(quán)限,因?yàn)樗麚碛蠷OLEJSER權(quán)限,所以可以訪問/index.jsp,因?yàn)樗麚碛蠷OLE_ADMIN權(quán)限,所以他可以訪問/admin.jsp。至此,我們很高興的宣布,咱們已經(jīng)正式完成,并運(yùn)行演示了一個最簡單的由SpringSecurity保護(hù)的web系統(tǒng),下ー步我們會深入討論SpringSecurity為我們提供的其他保護(hù)功能,多姿多彩的特性。第1章一個簡單的HelloWorldSpringSecurity中可以使用Acegi-1.x時代的普通配置方式,也可以使用從2.0時代オ出現(xiàn)的命名空間配置方式,實(shí)際上這兩者實(shí)現(xiàn)的功能是完全一致的,只是新的命名空間配置方式可以把原來需要幾百行的配置壓縮成短短的幾十行。我們的教程中都會使用命名空間的方式進(jìn)行配置,凡事務(wù)求最簡。1.配置過濾器為了在項(xiàng)目中使用SpringSecurity控制權(quán)限,首先要在web.xml中配置過濾器,這樣我們就可以控制對這個項(xiàng)目的每個請求了。<filter><filter-name>springSecurityFilterChain</filter-name><fi1ter-class>org.springframework.web.filter.De1egatingFi11erProxy</filter-class></filter><filter-mapping><filter-name>springSecurityFi1terChain</fi1ter-name><url-pattern>/*</url-pattern></filter-mapping>所有的用戶在訪問項(xiàng)目之前,都要先通過SpringSecurity的檢測,這從第一時間把沒有授權(quán)的請求排除在系統(tǒng)之外,保證系統(tǒng)資源的安全。關(guān)于過濾器配置的更多講解可以參考/tutorial/jsp/html/jsp-ch-07.html#jsp-ch-Q7-03-0I〇使用命名空間在applicationcontext,xml中使用SpringSecurity提供的命名空間進(jìn)行配置。<?xmlversion="1.0"encoding="UTF-8〃?><beans:beansxmlns="/schema/securityz,Oxmlns:beans二"/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation二/schema/beans/schema/beans/spring-beans-2.0.xsd/schema/security/schema/security/spring-security-2.0.4.xsd"><httpauto-config='true>?<intercept-urlpattern二"/admin,jspaccess二"ROLE_ADMIN"/>?<intercept-urlpatternニ〃/**"access二"ROLE_USER"/></http><authentication-provider><user-service><username二"admin"password二"admin"authorities="ROLE_USER,ROLE_ADMIN"ハ?<username二"userpassword二"user"authorities二"ROLE_USER〃/></user-service></authentication-provider></beans:beans>〇聲明在xm!中使用SpringSecurity提供的命名空間。?http部分配置如何攔截用戶請求。auto-config二'true’將自動配置兒種常用的權(quán)限控制機(jī)制,包括form,anonymous,rememberMeo?我們利用intercept-url來判斷用戶需要具有何種權(quán)限才能訪問對應(yīng)的url資源,可以在pattern中指定一個特定的url資源,也可以使用通配符指定ー組類似的url資源。例子中定義的兩個intercepter-url,第一個用來控制對/admin.jsp的訪問,第二個使用了通配符/**,說明它將控制對系統(tǒng)中所有url資源的訪問。在實(shí)際使用中,SpringSecurity采用的是ー種就近原則,就是說當(dāng)用戶訪問的url資源滿足多個intercepter-ur!時,系統(tǒng)將使用第一個符合條件的intercept-url進(jìn)行權(quán)限控制。在我們這個例子中就是,當(dāng)用戶訪問/admin.jsp時,雖然兩個intercept-url都滿足要求,但因?yàn)榈谝粋€intercept-url排在上面,所以SpringSecurity會使用第一個intercept-url中的配置處理對/admin,jsp的請求,也就是說,只有那些擁有了ROLE_ADMIN權(quán)限的用戶才能訪問/admin.jsp。access指定的權(quán)限部分比較有趣,大家可以注意到這些權(quán)限標(biāo)示符都是以ROLE_開頭的,實(shí)際上這與SpringSecurity中的Voter機(jī)制有著千絲萬縷的聯(lián)素,只有包含了特定前綴的字符串オ會被SpringSecurity處理。目前來說我們只需要記住這一點(diǎn)就可以了,在教程以后的部分中我們會詳細(xì)講解Voter的內(nèi)容。〇user-service中定義了兩個用戶,admin和user。為了簡便起見,我們使用明文定義了兩個用戶對應(yīng)的密碼,這只是為了當(dāng)前演示的方便,之后的例子中我們會使用SpringSecurity提供的加密方式,避免用戶密碼被他人竊取。最最重要的部分是authorities,這里定義了這個用戶登陸之后將會擁有的權(quán)限,它與上面intercept-ur!中定義的權(quán)限內(nèi)容 對應(yīng)。每個用戶可以同時擁有多個權(quán)限,例子中的admin用戶就擁有ROLE_ADMIN和ROLE_USER兩種權(quán)限,這使得admin用戶在登陸之后可以訪問ROLE_ADM1N和ROLE_USER允許訪問的所有資源。與之對應(yīng)的是,user用戶就只擁有ROLE_USER權(quán)限,所以他只能訪問ROLE_USER允許訪問的資源,而不能訪問ROLEADMIN允許訪問的資源。完善整個項(xiàng)目因?yàn)镾pringSecurity是建立在Spring的基礎(chǔ)之上的,所以web.xml中除了需要配置我們剛剛提到的過濾器,還要加上加載Spring的相關(guān)配置。最終得到的web.xml看起來像是這樣:<?xmlversion="1.0〃encoding二〃UTF-8〃?><web-appversion="2.4"xmlns="/xml/ns/j2ee"xmlns:xsi=/2001/XMLSchema-instancexsi:schemaLocation="/xml/ns/j2ee/xml/ns/j2ee/web_app_2_4.xsd><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext*.xml</param-va1ue></context-param><filter><fi1ter-name>springSecurityFilterChain</filter-name>
<fi1ter-class>org.springframework.web.filter.De1egatingFi11erProxy</filter-class></filter><filter-mapping><filter-name>springSecurityFilterChain</filter-name>くurl-pattern〉/*く/url-pattern)</filter-mapping><listener>くlistener-class〉org.springframework.web.context.ContextLoaderListenerく/listener-class〉</listener></web-app>演示不同權(quán)限的用戶登陸之后可以訪問不同的資源,我們?yōu)轫?xiàng)目添加了兩個jsp文件,admin,jsp和index.jspo其中admin,jsp只有那些擁有ROLE_ADMIN權(quán)限的用戶才能訪問,而index.jsp只允許那些擁有ROLE_USER權(quán)限的用戶才能訪問。最終我們的整個項(xiàng)目會變成下面這樣:+chOOl/+src/+main/+resources/*applicationContext.xml+webapp/+WEB-INF/*web.xmladmin,jspindex,jsp+test/+resources/*pom.xml1.4.運(yùn)行示例首先確保自己安裝了Maven2。如果之前沒用過Maven2,可以參考我們的Maven2教程ht卬:///oa/maven2/html/index,html〇
安裝好Maven2之后,進(jìn)入chOOl目錄,然后執(zhí)行mvn。信息:RootWebApplicationContext:initializationcompletedin1578ms2009-05-2811:37:50.171::INF0:StartedSelectChannelConnector@:8080[INFO]StartedJettyServer[INFO]Startingscanneratintervalof10seconds.等到項(xiàng)目啟動完成后。打開瀏覽器訪問http:〃localhost:8080/chOOl/就可以看到登陸頁面。LoginwithUsernameandPasswordUser:Password:|「Remembermeonthiscomputer.提交查詢I重置圖1.1.用戶登陸這個簡陋的頁面是SpringSecurity自動生成的,一來為了演示的方便,二來避免用戶自己編寫登陸頁面時犯錯,SpringSecurity為了避免可能出現(xiàn)的風(fēng)險(xiǎn),連測試用的登錄頁面都自動生成出來了。在這里我們就省去編寫登陸頁面的步驟,直接使用默認(rèn)生成的登錄頁面進(jìn)行演示吧。首先讓我們輸入ー個錯誤用的用戶名或密碼,這里我們使用test/test,當(dāng)然這個用戶是不存在的,點(diǎn)擊提交之后我們會得到這樣ー個登陸錯誤提示頁面。Yourloginattemptwasnotsuccessful,tryagain.Reason:BadcredentialsLoginwithUsernameandPasswordUser: (testPassword:|「 Remembermeonthiscomputer.提交查詢I重置圖L2.登陸失敗如果輸入的是正確的用戶名和密碼,比如user/user,系統(tǒng)在登陸成功后會默認(rèn)跳轉(zhuǎn)到!ndex.jsp?username:useradmin,jsplogout圖1.3.登陸成功這時我們可以點(diǎn)擊admin.jsp鏈接訪問admin.jsp?也可以點(diǎn)擊logout進(jìn)行注銷。如果點(diǎn)擊了logout,系統(tǒng)會注銷當(dāng)前登陸的用戶,然后跳轉(zhuǎn)至登陸頁面。如果點(diǎn)擊了admin.jsp鏈接就會顯示如下頁面。HTTPERROR403ProblemaccessingZhelloworld/adminjsp.Reason:AccessisdeniedPoweredbyJetty://圖1.4.拒絕訪問很遺憾,user用戶是無法訪問/admin.jsp這個url資源的,這在上面的配置文件中已經(jīng)有過深入的討論。我們在這里再簡要重復(fù)一遍:user用戶擁有ROLE_USER權(quán)限,但是/admin.jsp資源需要用戶擁有ROLE_ADMIN權(quán)限才能訪問,所以當(dāng)user用戶視圖訪問被保護(hù)的/admin.jsp時,SpringSecurity會在中途攔截這ー請求,返回拒絕訪問頁面。為了正常訪問admin,jsp,我們需要先點(diǎn)擊logout注銷當(dāng)前用戶,然后使用admin/admin登陸系統(tǒng),然后再次點(diǎn)擊admin,jsp鏈接就會顯示出admin,jsp中的內(nèi)容。admin,jsp圖1.5.顯ホadmin,jsp根據(jù)我們之前的配置,admin用戶擁有ROLE_ADMIN和ROLE_USER兩個權(quán)限,因?yàn)樗麚碛蠷OLEJJSER權(quán)限,所以可以訪問/index,jsp,因?yàn)樗麚碛蠷OLE_ADMIN權(quán)限,所以他可以訪問/admin.jsp。至此,我們很高興的宣布,咱們已經(jīng)正式完成,并運(yùn)行演示了一個最簡單的由SpringSecurity保護(hù)的web系統(tǒng),下ー步我們會深入討論SpringSecurity為我們提供的其他保護(hù)功能,多姿多彩的特性。第2章使用數(shù)據(jù)庫管理用戶權(quán)限上??章節(jié)中,我們把用戶信息和權(quán)限信息放到了xml文件中,這是為了演示如何使用最小的配置就可以使用SpringSecurity,而實(shí)際開發(fā)中,用戶信息和權(quán)限信息通常是被保存在數(shù)據(jù)庫中的,為此SpringSecurity提供了通過數(shù)據(jù)庫獲得用戶權(quán)限信息的方式。2.1.修改配置文件為了從數(shù)據(jù)庫中獲取用戶權(quán)限信息,我們所需要的僅僅是修改配置文件中的authentication-provider部分。將上一?章配置文件中的user-service替換為jdbc-user-service,替換內(nèi)容如下所示:
<authentication-provider>くusoLsorvic。?3-Rame二〃admin"password二〃admin"authorilies二〃ROLEUSER,ROLE_ADMIN〃/>(username二〃user〃password二〃user〃authorities二〃ROLEUSER〃/>く/usor-sorvic。)</authentication-provider>將上述紅色部分替換為下面黃色部分。くauthentication-provider)<jdbc-user-servicedata-source-ref二〃dataSource〃/)</authentication-provider>現(xiàn)在只要再為jdbc-user-service提供ー1個dataSource就可以讓SpringSecurity使用數(shù)據(jù)庫中的權(quán)限信息了。在此我們使用spring創(chuàng)建一?個演示用的dataSource實(shí)現(xiàn),這個dataSource會連接到hsqldb數(shù)據(jù)庫,從中獲取用戶權(quán)限信自用<beans:beanid二〃dataSource〃class二"org?springframework.jdbc.datasource.DriverManagerDataSource,z><beans:propertyname二driverClassName,zvalue二〃org.hsqldb.jdbcDriver/><beans:propertyname二〃url〃value二jdbc:hsqldb:res:/hsqldb/test/><beans:propertyname二username〃value二〃sa〃/)<beans:propertyname二password〃value二/〉</beans:bean>最終的配置文件如下所示:<?xmlversion二〃1.0〃encoding二〃UTF-8〃?><beans:beansxmlns二〃http://www.springframework,org/schema/security^xmlns:beans二"/schema/beansxmlns:xsi二〃/2001/XMLSchema-instance〃xsi:schemaLocation二/schema/beanshttp://www.springframework,org/schema/beans/spring-beans-2.0.xsd/schema/security/schema/security/spring-security-2.0.4.xsd〃>
<httpauto-config=,true,><intercept-urlpattern="/admin,jsp"access="ROLE_ADMIN"/><intercept-urlpattern="/**〃access="ROLE_USER〃/></http><authentication-provider><jdbc-user-servicedata-source-ref="dataSource/></authentication-provider><beans:beanid二"dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><beans:propertyname二"driverClassName"value二org.hsqldb.jdbcDriver"/><beans:propertyname二"url"value二jabc:hsqldb:res:/hsqldb/test"/><beans:propertyname二"username"value二"sa"/><beans:propertyname="password"value=""/></beans:bean></beans:beans>2.數(shù)據(jù)庫表結(jié)構(gòu)SpringSecurity默認(rèn)情況下需要兩張表,用戶表和權(quán)限表。以下是hsqldb中的建表語句:createtableusers(0usernamevarchar_ignorecase(50)notnullprimarykey,passwordvarchar_ignorecase(50)notnull,enabledbooleannotnull);createtableauthorities(?usernamevarchar_ignorecase(50)notnull,authorityvarchar_ignorecase(50)notnull,constraintfk_authorities_usersforeignkey(username)referencesusers(username));createuniqueindexix_auth_usernameonauthorities(username,authority);?Ousers:用戶表。包含username用戶登錄名,password登陸密碼,enabled用戶是否被禁用三個字段。其中username用戶登錄名為主鍵。?authorities:權(quán)限表。包含username用戶登錄名,authorities對應(yīng)權(quán)限兩個字段。其中username字段與users用戶表的主鍵使用外鍵關(guān)聯(lián)。?對authorities權(quán)限表的username和authority創(chuàng)建唯一索引,提高查詢效率。SpringSecurity會在初始化時,從這兩張表中獲得用戶信息和對應(yīng)權(quán)限,將這些信息保存到緩存中。其中users表中的登錄名和密碼用來控制用戶的登錄,而權(quán)限表中的信息用來控制用戶登陸后是否有權(quán)限訪問受保護(hù)的系統(tǒng)資源。我們在示例中預(yù)先初始化了一部分?jǐn)?shù)據(jù):insertintousers(username,password,enabled)values('admin','admin,,true);insertintousers(username,password,enabled)values('user','user',true);insertintoauthorities(username,authority)values('admin','ROLE_ADMIN');insertintoauthorities(username,authority)values('admin','ROLE_USER');insertintoauthorities(username,authority)values('user','ROLE_USER');上述sql中,我們創(chuàng)建了兩個用戶admin和user,其中admin擁有ROLE_ADMIN和ROLE_USER權(quán)限,而user只擁有R0LEJSER權(quán)限。這和我們上一章中京配置相同,由此本章實(shí)例的效果也和上一章完全相同,這里就不再贅述了。實(shí)例見ch002。[しjavax.sql.Datasource是ー個用來定義數(shù)據(jù)庫連接池的統(tǒng)ー接口。當(dāng)我們想調(diào)用任何實(shí)現(xiàn)了javax.sql.DalaSource接U的連接池,只需要調(diào)用接口提供的getConneclion()就可以獲得連接池中的jdbc連接。javax.sql.DataSource可以屏蔽連接池的不同實(shí)現(xiàn),我們使用的連接池即可能由第三方包單獨(dú)提供,也可能是由j2ee容器統(tǒng)ー管理提供的。第3章自定義數(shù)據(jù)庫表結(jié)構(gòu)SpringSecurity默認(rèn)提供的表結(jié)構(gòu)太過簡單了,其實(shí)就算默認(rèn)提供的表結(jié)構(gòu)很復(fù)雜,也無法滿足所有企業(yè)內(nèi)部對用戶信息和權(quán)限信息管理的要求?;旧厦總€企業(yè)內(nèi)部都有一套自己的用戶信息管理結(jié)構(gòu),同時也會有…套對應(yīng)的權(quán)限信息體系,如何讓SpringSecurity在這些已有的數(shù)據(jù)結(jié)構(gòu)之上運(yùn)行呢?1?自定義表結(jié)構(gòu)假設(shè)我們實(shí)際使用的表結(jié)構(gòu)如下所示:~角色createtablerole(idbigint,namevarchar(50),descnvarchar(200));altertableroleaddconstraintpk_roleprimarykey(id);altertablerolealtercolumnidbigintgeneratedbydefaultasidentity(startwith1);ー用戶createtableuser(idbigint,usernamevarchar(50),passwordvarchar(50),statusinteger,descnvarchar(200));altertableuseraddconstraintpk_userprimarykey(id);altertableuseraltercolumnidbigintgeneratedbydefaultasidentity(startwith1);~用戶角色連接表createtableuser_role(user_idbigint,role_idbigint);altertableuser_roleaddconstraintpk_user_roleprimarykey(user_id,role_id);
altertableuser_roleaddconstraintfk_user_role_userforeignkey(user_id)referencesuser(id);altertableuser_roleaddconstraintfk_user_r〇1e_r〇1eforeignkey(role_id)referencesrole(id);上述共有三張表,其中user用戶表,role角色表為保存用戶權(quán)限數(shù)據(jù)的主表,user_role為關(guān)聯(lián)表。user用戶表,role角色表之間為多對多關(guān)系,就是說ー個用戶可以有多個角色。ER圖如下所示:USERIDBIGINT(O)STATUSINTEGER(0)PASSWORDVARCHAR(50)USERNAMEVARCHAR(50)DESCNVARCHAR(200)XFK_USER_ROIE_USERUSER_ROLE國ROLE」DBIGINT(O)SJUSER.IDBIGINT(O)FK_USER_ROIE_ROLEROLEQIDBIGINT(O)NAMEVARCHAR(50)DESCNVARCHAR(200)圖3.1.數(shù)據(jù)庫表關(guān)系3.2,初始化數(shù)據(jù)創(chuàng)建兩個用戶,admin和user。admin用戶擁有"管理員"角色,user用戶擁有"用戶”角色。
insertintouser(id,username,password,status,descn)values(1,'admin','admin',1,,管理員');insertintouser(id,username,password,status,descn)values(2,'user','user',1,'用戶');insertintorole(id,name,descn)values(1,'ROLE_ADMIN','管理員角色');insertintorole(id,name,descn)values(2,'ROLE_USER','用戶角色');insertintouser_role(user_id,role_id)values(1,1);insertintouser_role(user_id,role_id)values(1,2);insertintouser_role(user_id,role_id)values(2,2);3.獲得自定義用戶權(quán)限信息現(xiàn)在我們要在這樣的數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)上使用SpringSecurity,SpringSecurity所需要的數(shù)據(jù)只是為了處理兩種情況,ー是判斷登錄用戶是否合法,二是判斷登陸的用戶是否有權(quán)限訪問受保護(hù)的系統(tǒng)資源。我們所要做的工作就是在現(xiàn)有數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)上,為SpringSecurity提供這兩種數(shù)據(jù)。處理用戶登陸當(dāng)用戶登陸時,系統(tǒng)需要判斷用戶登錄名是否存在,登陸密碼是否正確,當(dāng)前用戶是否被禁用。我們使用下列SQL來提取這三個信息。selectusername,password,statusasenabledfromuserwhereusername=?檢驗(yàn)用戶權(quán)限用戶登陸之后,系統(tǒng)需要獲得該用戶的所有權(quán)限,根據(jù)用戶已被賦予的權(quán)限來判斷哪些系統(tǒng)資源可以被用戶訪問,哪些資源不允許用戶訪問。以下SQL就可以獲得當(dāng)前用戶所擁有的權(quán)限。selectu.username,asauthorityfromuserujoinuser_roleuronu.id=ur.user_idjoinroleronr.id=ur.role_idwhereu.username=?〃/〉將這兩條SQL語句配置到xml中,就可以讓SpringSecurity從我們自定義的表結(jié)構(gòu)中提取數(shù)據(jù)了。最終配置文件如下所示:<authentication-provider><jdbc-user-servicedata-source-ref=〃dataSource”?users-by-username-query=selectusername,password,statusasenabledfromuserwhereusername二?〃?authorities-by-username-query二〃selectu.username,asauthorityfromuserujoinuser_roleuronu.id二ur.user_idjoinroleronr.id二ur.role_idwhereu.username二?”/)</authentication-provider>Ousers-by-usemame-query為根據(jù)用戶名査找用戶,系統(tǒng)通過傳入的用戶名查詢當(dāng)前用戶的登錄名,密碼和是否被禁用這ー狀態(tài)。?authorities-by-username-query為根據(jù)用戶名查找權(quán)限,系統(tǒng)通過傳入的用戶名查詢當(dāng)前用戶已被授予的所有權(quán)限。實(shí)例見ch003。第4章自定義登陸頁面SpringSecurity雖然默認(rèn)提供了?個登陸頁面,但是這個頁面實(shí)在太簡陋了,只有在快速演示時才有可能它做系統(tǒng)的登陸頁面,實(shí)際開發(fā)時無論是從美觀還是實(shí)用性角度考慮,我們都必須實(shí)現(xiàn)自定義的登錄頁面。1.實(shí)現(xiàn)自定義登陸頁面
自己實(shí)現(xiàn)ー個!ogin.jsp,放在src/main/webapp/目錄下。+ch004/+src/+main/+resources/*applicationContext.xml+webapp/+WEB-INF/*web.xmladmin,jspindex,jsplogin,jsp+test/+resources/*pom.xml4.2.修改配置文件在xml中的http標(biāo)簽中添加一個form-login標(biāo)簽。<httpauto-config='true'><intercept-urlpattern二/login,ispaccess二〃ISAUTHENTICATEDANONYMOUSLY”/>?くintercept-urlpattern二"/admin,jsp"access="ROLE_ADMIN"/><intercept-urlpattern="/**"access="ROLE_USER"/>くform-loginlogin二/login,isp”?authentication-failure-url二"/login,jsp?error二true〃?default-target-url二/"/〉?</http>O讓沒登陸的用戶也可以訪問login.jsp。國這是因?yàn)榕渲梦募械摹?**”配置,要求用戶訪問任意一個系統(tǒng)資源時,必須擁有ROLE_USER角色,/login.jsp也不例外,如果我們不為/login.jsp單獨(dú)配置訪問反限,會造成用戶連登陸的權(quán)限都沒有,這是不正確的。?login表示用戶登陸時顯示我們自定義的login.jsp0這時我們訪問系統(tǒng)顯示的登陸頁面將是我們上面創(chuàng)建的login.jspo?authentication-failure-url表示用戶登陸失敗時,跳轉(zhuǎn)到哪個頁面。
當(dāng)用戶輸入的登錄名和密碼不正確時,系統(tǒng)將再次跳轉(zhuǎn)到/login.jsp,并添加一?個error=true參數(shù)作為登陸失敗的標(biāo)示。〇default-target-url表示登陸成功時,跳轉(zhuǎn)到哪個頁面?!?.3.登陸頁面中的參數(shù)配置以下是我們創(chuàng)建的login.jsp頁面的主要代碼。<divclass二〃error${param,error==true? :'hide}”>登陸失敗くbr>${sessionScopefSPRING_SECURITY_LAST_EXCEPTION,].message}</div><formaction="${pageContext.request.contextPath}/j_spring_security_checkO"style二〃width:260px;text-align:center;<fieldset>くlegend》登陸く/legend)用戶:<inputtype二text“name="j_username?"style二width:150px;"value二〃${sessionScopefSPRING_SECURITY_LAST_USERNAME,]}"/Xbr/>密碼:<inputtype二〃password“name二j_password?style二〃width:150px;"/Xbr/><inputtype二"checkbox"name="_spring_security_remember_meO'/>兩周之內(nèi)不必登陸くbr/><inputtype二"submitvalue二登陸”/〉<inputtype二"reset"value二“重置”/〉</fieldset></form>?/j_spring_security_check,提交登陸信息的URL地址。自定義form時,要把form的action設(shè)置為/j_spring_security_check。注意這里要使用絕對路徑,避免登陸頁面存放的頁面可能帶來的問題。國?j_username,輸入登陸名的參數(shù)名稱。?j_password,輸入密碼的參數(shù)名稱0_springsecurityrememberme,選擇是否允許自動登錄的參數(shù)名稱??梢灾苯影堰@個參數(shù)設(shè)置為ー個checkbox,無需設(shè)置value,SpringSecurity會自行判斷它是否被選中。以上介紹了自定義頁面上SpringSecurity所需的基本元素,這些參數(shù)名稱都采用了SpringSecurity中默認(rèn)的配置值,如果有特殊需要還可以通過配置文件進(jìn)行修改。4,測試一下經(jīng)過以上配置,我們終于使用了一個自己創(chuàng)建的登陸頁面替換了原來SpringSecurity默認(rèn)提供的登錄頁面了。我們不僅僅是做個樣子,而是實(shí)際配置了各個SpringSecurity所需的參數(shù),真正將自定義登陸頁面與SpringSecurity緊緊的整合在了一起。以下是使用自定義登陸頁面實(shí)際運(yùn)行時的截圖?!傅顷懸挥脩?密碼:「兩周之內(nèi)不必登陸
一登陸丨重置]圖4.1.進(jìn)入登錄頁面登陸失敗. Badcredentials_一彝 用戶:[wrong密碼:|~廠兩周之內(nèi)不必登陸
一登陸I重置]圖4.2.用戶登陸失敗實(shí)例見ch004o目有關(guān)匿名用戶的知識,我們會在之后的章節(jié)中進(jìn)行講解。登陸成功后跳轉(zhuǎn)策略的知識,我們會在之后的章節(jié)中進(jìn)行講解。國關(guān)于絕對路徑和相對路徑的詳細(xì)討論,請參考/tutorial/jsp/html/jsp-ch-03.html#jsp-ch-03-04-01第5章使用數(shù)據(jù)庫管理資源國內(nèi)對權(quán)限系統(tǒng)的基本要求是將用戶權(quán)限和被保護(hù)資源都放在數(shù)據(jù)庫里進(jìn)行管理,在這點(diǎn)上SpringSecurity并沒有給出官方的解決方案,為此我們需要對SpringSecurity進(jìn)行擴(kuò)展。1.數(shù)據(jù)庫表結(jié)構(gòu)這次我們使用五張表,user用戶表,role角色表,resc資源表相互獨(dú)立,它們通過各自之間的連接表實(shí)現(xiàn)多對多關(guān)系。~資源createtableresc(idbigint,namevarchar(50),res_typevarchar(50),res_stringvarchar(200),priorityinteger,descnvarchar(200));altertablerescaddconstraintpk_rescprimarykey(id);altertablerescaltercolumnidbigintgeneratedbydefaultasidentity(startwith1);一角色createtablerole(idbigint,namevarchar(50),descnvarchar(200));altertableroleaddconstraintpk_roleprimarykey(id);altertablerolealtercolumnidbigintgeneratedbydefaultasidentity(startwith1);ー用戶createtableuser(idbigint,usernamevarchar(50),passwordvarchar(50),statusinteger,descnvarchar(200));altertableuseraddconstraintpk_userprimarykey(id);altertableuseraltercolumnidbigintgeneratedbydefaultasidentity(startwith1);~資源角色連接表createtableresc_role(resc_idbigint,role_idbigint);altertableresc_roleaddconstraintpk_resc_roleprimarykey(resc_id,role_id);altertableresc_roleaddconstraintfk_resc_role_rescforeignkey(rescid)referencesresc(id);altertableresc_roleaddconstraintfk_resc_r〇1e_r〇1eforeignkey(role_id)referencesrole(id);ー用戶角色連接表createtableuser_role(user_idbigint,role_idbigint);altertableuser_roleaddconstraintpk_user_roleprimarykey(user_id,role_id);altertableuser_roleaddconstraintfk_user_r〇1e_userforeignkey(user_id)referencesuser(id);altertableuser_roleaddconstraintfk_user_role_ro1eforeignkey(role_id)referencesrole(id);user表中包含用戶登陸信息,role角色表中包含授權(quán)信息,resc資源表中包含需要保護(hù)的資源。ER圖如下所示:
USER□IDBIGINT(O)ROLERESC□IDBIGIhTT(O)FK_USERFKUSERROkEUSERIDBIGINT(O)FKRESCRNAIEVARCHAR(50)DESCNVARCHAR(200)STATUSINTEGER(0)PASSWORDVARCHAR(50)USERNAMEVARCHAR(50)DESCNVARCHAR(200)RES_TYPEVARCHAR(50PRIORITYINTEGER(0)NAIEVARCHAR(50)RESSTRINGVARCHAR(DESCNVARCHAR(200)USER□IDBIGINT(O)ROLERESC□IDBIGIhTT(O)FK_USERFKUSERROkEUSERIDBIGINT(O)FKRESCRNAIEVARCHAR(50)DESCNVARCHAR(200)STATUSINTEGER(0)PASSWORDVARCHAR(50)USERNAMEVARCHAR(50)DESCNVARCHAR(200)RES_TYPEVARCHAR(50PRIORITYINTEGER(0)NAIEVARCHAR(50)RESSTRINGVARCHAR(DESCNVARCHAR(200)ROROLEFKRESCRORESCUSERROLERESCROLEEROLE.IDBIGINT(O)
困USER_IDBIGINT(O)國ROLE」DBIGINT(O)S3RESC_IDBIGINT(O)圖5.1.數(shù)據(jù)庫表關(guān)系5.2,初始化數(shù)據(jù)創(chuàng)建的兩個用戶分別對應(yīng)“管理員”角色和“用戶”角色。而“管理員”角色可以訪問“/admin.jsp”和“/**”,“用戶”角色只能訪問“/**”。insertintouser(id,username,password,status,descn)values(1,*admin','admin',1,,管理員’);insertintouser(id,username,password,status,descn)values(2,'user','user',1,'用戶’);insertintorole(id,name,descn)values(1,'ROLE_ADMIN','管理員角色');insertintorole(id,name,descn)values(2,'ROLE_USER','用戶角色');insertintoresc(id,name,res_type,res_string,priority,descn)values(1,'','URL','/admin,jsp',1,'');insertintoresc(id,name,res_type,res_string,priority,descn)values(2,'','URL'2,'');insertintoresc_role(resc_id,role_id)values(1,1);insertintoresc_role(resc_id,role_id)values(2,1);insertintoresc_role(resc_id,role_id)values(2,2);insertintouser_role(user_id,role_id)values(1,1);
insertintouser_role(user_id,role_id)values(1,2);insertintouser_role(user_id,role_id)values(2,2);3.實(shí)現(xiàn)從數(shù)據(jù)庫中讀取資源信息SpringSecurity沒有提供從數(shù)據(jù)庫獲得獲取資源信息的方法,實(shí)際上SpringSecurity甚至沒有為我們留一個半個的擴(kuò)展接口,所以我們這次要費(fèi)點(diǎn)兒腦筋了。首先,要搞清楚需要提供何種類型的數(shù)據(jù),然后,尋找可以讓我們編寫的代碼替換原有功能的切入點(diǎn),實(shí)現(xiàn)了以上兩步之后,就可以宣布大功告成了。需要何種數(shù)據(jù)格式從配置文件上可以看到,SpringSecurity所需的數(shù)據(jù)應(yīng)該是??系列URL網(wǎng)址和訪問這些網(wǎng)址所需的權(quán)限:<intercept-urlpattern="/login.jsp”access=z,IS_AUTHENTICATED_ANONYMOUSLY,//><intercept-urlpattern=/admin,jspaccess="ROLE一ADMIN”/><intercept-urlpattern—'/**''access="ROLE_USER"/>SpringSecurity所做的就是在系統(tǒng)初始化時,將以上XML中的信息轉(zhuǎn)換為特定的數(shù)據(jù)格式,而框架中其他組件可以利用這些特定格式的數(shù)據(jù),用于控制之后的驗(yàn)證操作?,F(xiàn)在這些資源信息都保存在數(shù)據(jù)庫中,我們可以使用上面介紹的SQL語句從數(shù)據(jù)中查詢。selectre.res_string,fromrolerjoinresc_rolerronr.id=rr.role_idjoinrescreonre.id=rr.resc_idorderbyre.priority下面要開始編寫實(shí)現(xiàn)代碼了。搜索數(shù)據(jù)庫獲得資源信息。我們通過定義ー個MappingSqlQuery實(shí)現(xiàn)數(shù)據(jù)庫操作。privateclassResourceMappingextendsMappingSqlQuery{protectedResourceMapping(DataSourcedataSource,StringresourceQuery){super(dataSource,resourceQuery);compile();)protectedObjectmapRow(ResultSetrs,intrownum)throwsSQLException{Stringurl=rs.getString(l);Stringrole=rs.getString(2);Resourceresource=newResource(url,role);returnresource;這樣我們可以執(zhí)行它的execute。方法獲得所有資源信息。protectedMap<String,String>findResources(){ResourceMappingresourceMapping=newResourceMapping(getDataSource(),resourceQuery);Map<String,String>resourceMap=newLinkedHashMap<String,StringX);for(Resourceresource:(List<Resource?resourceMapping.execute()){Stringurl=resource.getUrl();Stringrole=resource.getRole。;if(resourceMap.containsKey(url)){Stringvalue=resourceMap.get(url);resourceMap.put(url,value+'+role);}else{resourceMap.put(url,role);)returnresourceMap;使用獲得的資源信息組裝requestMtectedLinkedHashMap<RequestKey,ConfigAttributeDefinition>buiIdRequestMap(){LinkedHashMap<RequestKey,ConfigAttributeDefinition>requestMap=null;requestMap=newLinkedHashMap<RequestKey,ConfigAttributeDefinition>();ConfigAttributeEditoreditor=newConfigAttributeEditor();Map<String,String>resourceMap=this,findResources();for(Map.Entry<String,String>entry:resourceMap.entrySet()){RequestKeykey=newRequestKey(entry.getKey(),null);editor.setAsText(entry.getValue());requestMap.put(key,(ConfigAttributeDefinition)editor.getValue());)returnrequestMap;).使用urlMatcher和requestMap創(chuàng)建DefaultFilterlnvocationDefinitionSourceopublicObjectgetObject(){returnnewDefaultFilterlnvocationDefinitionSource(this.getUrlMatcher(),this,buiIdRequestMap());)這樣我們就獲得了DefaultFilterlnvocationDefinitionSource?剩下的只差把這個我們自己創(chuàng)建的類替換掉原有的代碼了。完整代碼如下所示:packagecom.familyl68.springsecuritybook.ch005;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.util.LinkedHashMap;importjava.util.List;importjava.util.Map;importjavax.sql.DataSource;importorg.springframework.beans,factory.FactoryBean;importorg.springframework.jdbc.core,support.JdbcDaoSupport;importorg.springframework.jdbc.object.MappingSqlQuery;importorg.springframework.security.ConfigAttributeDefinition;importorg.springframework.security.ConfigAttributeEdi
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 內(nèi)蒙古烏蘭察布市(2024年-2025年小學(xué)五年級語文)統(tǒng)編版小升初真題(下學(xué)期)試卷及答案
- 塔式起重機(jī)與其他機(jī)械協(xié)同作業(yè)方案
- 機(jī)器人產(chǎn)業(yè)全過程工程咨詢實(shí)施方案
- 高層建筑消防安全制度探索
- 社區(qū)醫(yī)院后勤管理制度優(yōu)化方案
- 班級后進(jìn)生行為規(guī)范轉(zhuǎn)化方案
- 《保理合同法律問題研究》
- 邢臺學(xué)院《應(yīng)用翻譯》2022-2023學(xué)年第一學(xué)期期末試卷
- xx集團(tuán)辦公樓抗震改造工程方案
- 糖尿病口服降糖藥物分類
- 4.1數(shù)列的概念(第2課時)-高中數(shù)學(xué)人教A版(2019)選擇性必修第二冊
- 英文科技論文寫作的100個常見錯誤
- 新湘科版小學(xué)三年級科學(xué)上冊-全冊教案
- 2023飛輪儲能技術(shù)在新能源一次調(diào)頻上的應(yīng)用
- 第7講-化學(xué)工程的倫理問題-201912092040097
- 激素類藥物使用規(guī)范
- 全面預(yù)算管理項(xiàng)目啟動培訓(xùn)課件PPT
- 北師大版2023-2024五年級數(shù)學(xué)上冊期中測試卷
- 第十六章-組織創(chuàng)新-管理學(xué)馬工程-課件
- 全球航路的開辟(共31張)
- 東方管理智慧儒道禪的視閾
評論
0/150
提交評論