javascript
Spring3之Security
1.spring security介紹
? Spring Security原來叫做Acegi Security,可用于加強任何Java應用的安全,但是最常用于基于Web的應用。下面首先理解幾個安全術語:
驗證:是驗證一個角色與其聲稱的身份相符的過程。這個角色可以是一個用戶、一個設備或者一個系統,但是最典型的是一個用戶。角色必須提供身份證據進行驗證。這個證據稱作憑據,當目標角色是用戶時通常是一個密碼。
授權:是向已驗證的用戶授予權限,使其能夠訪問目標應用的特定資源的過程。收全過程必須在驗證過程之后進行。一般來說,權限按照角色授予。
訪問控制:意指控制對應應用資源的訪問。訪問控制必須作出用戶是否允許訪問某個資源的決策,這個決策稱為訪問控制決策。?通過比較資源的訪問屬性和用戶被授予的權限或者其他特性作出。
?
2.基本配置
Spring Security的安全控制是通過?一系列的ServletRequest過濾器實現的。Spring Security提供配置DelegatingFilterProxy攔截包裝所有的URL請求,委托給其他的過濾器,因此在web.xml中配置此過濾器,如下:
??<filter>
<filter-name>springSecurityFilterChain</filter-name>????????<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
????</filter>
????<filter-mapping>
????????<filter-name>springSecurityFilterChain</filter-name>
????????<url-pattern>/*</url-pattern>
????</filter-mapping>
?集成Web環境的通用配置,當然需配置加載所有的Bean的ContextLoadListener,或者其他配置方式。
從基本配置可以看出Spring Security的主要依賴于這些代理和過濾器,來實現請求的安全控制。Spring Security在自動配置中建立了一些過濾器,這些過濾器都是按照鏈順序組合的,servlet請求按照一定的順序從一個過濾器到下一個穿過整個過濾器鏈,最終到達目標servlet,當然響應就倒過來傳了。而S-Security擁有更多的過濾器,能根據請求改變控制行為。S-Security提供了相應的組件來進行認證,如AuthenticationManager接口來驗證用戶的憑證信息,Authentication接口獲取用戶的詳細信息。在默認過濾鏈中,最后一個過濾器是FilterSecurityInterceptor,它的作用是判斷請求是允許還是要拒絕。S-Security使用訪問決策控制器組件來負責做出決策,如AccessDecisionManager接口,我們可以實現完全的自定義授權機制配置,如投票器和訪問決策器的配置。
??
3.url的安全
S-Security通過簡單的配置,以聲明式的方法加強應用的URL訪問安全,當然同樣才用過濾器來處理。如果我們Web應用的安全需求是簡單而典型,這可以將autoconfig屬性設置為true,這樣Spring Security就會自動注冊和配置一些基本服務,如基于表單的登陸注銷,匿名登錄,HTTP基本驗證,Remember-me等。其通過一個或者多個<intercept-url>元素限制對特定URL的訪問,每個<intercept-url>元素指定一個URL模式,以及一個訪問這些URL所需的訪問屬性。我們大都使用SpEL來實現這些訪問屬性的控制。如下配置:
? ??<http?auto-config="true">
? ??<intercept-url?pattern="/login.jsp*"?access="IS_AUTHENTICATED_ANONYMOUSLY"?/>? ? ? ? ? ??<intercept-url?pattern="/messagePost*"?access="ROLE_USER"?/>
? ? ? ? ? ??<intercept-url?pattern="/messageDelete"?access="ROLE_ADMIN"??/>
? ? ? ? ? ??<intercept-url?pattern="/**"?access="IS_AUTHENTICATED_FULLY"?/>?
? ? ? </http>
? 還可以在<authentication-provider>元素中配置驗證服務,就在我們上述講到的<authentication-manager>內,S-security支持很多驗證方法,也可以自定義驗證策略。
4.web登錄的安全
?安全的Web登陸在互聯網上尤其重要,S-security支持多種用戶登錄Web應用的方法,有包含登陸表單的默認網頁,匿名登錄,remember-me登陸等。HTTP基本驗證支持可以通過<http-basic>元素配置,如果基本驗證和基于表單的登陸同時啟用,將會使用后者。
基于表單的登陸服務將顯示一個包含登陸表單的網頁,通過<form-login>元素來配置,默認情況下,S-security自動創建一個登陸頁面并將其映射到URL /spring_security_login。如下: <a href="<c:url value="/spring_security_login" />" Log in </a> ?,當然如果我們自定義登陸頁面需如有如下幾部分大致如下:
?<form?method="POST"?action="<c:url?value="/j_spring_security_check"?/>"?>
<table>????????<tr><td>Username</td>
????????????<td><input?type="text"?name="j_username"/></td>
????????</tr>
????????<tr><td>Password</td>
????????????<td><input?type="password"?name="j_password"?/></td>
????????</tr>
????????<tr><td>Remember?Me</td>
????????????<td><input?type="checkbox"?name="_spring_security_remember_me"?/></td>
????????</tr>
????????<tr><td>
????????????<input?type="submit"?value="Login"/>
????????????<input?type="reset"?value="Reset"?/>
????????????</td></tr>
</table></form>
?默認在成功登陸后進入項目根目錄,如果想要重定向到別的目錄可以在<form-login>中的default-target-url屬性來配置,如果登陸失敗可通過authentication-failure-url屬性配置,想要知道發生了什么錯誤,可以通過訪問會話范圍內的SPRING_SECURITY_LAST_EXCEPTION來顯示。
注銷服務通過<logout>配置,默認映射到URL /j_spring_security_logout,與login類似的配置。此外匿名登錄通過在<http>內的<anonymous/>配置,Remember-me通過<remember-me/>配置,靜態的remember-me可能導致安全問題,因此可以存儲到數據庫使用滾動令牌。
?
5.驗證用戶
? S-security支持多種驗證方法,包括這些方法的內建提供者實現,大部分常見的額驗證提供者利用存儲用戶細節的用戶存儲庫,如內存、關系數據庫、LDAP存儲庫等驗證用戶。存儲時務必要使用密文存儲,通常使用單向散列函數(如MD5和SHA)進行編碼,Spring提供了這些算法的內建密碼編碼器。
如果應用中有少數用戶,并且很少修改用戶細節,可以考慮直接配在配置文件中加載到內存中認證,在<user-service>中定義用戶細節,也可以寫到屬性文件中去。
較多的我們還是將用戶細節存儲到數據庫中,這樣更容易維護。同樣我們要建立相應的表和列,并在,<authentication-provider>中加入<jdbc-user-service>配置,用來查詢數據庫獲得用戶細節。但是我們自己的用戶表,不可能和它完全一致,spring支持用自定義的SQL語句查詢用users-by-username-query和authorities-by-username-query屬性自定查詢和授權語句。既然密碼需要用密文來存放,則我們需要自己指定使用的加密算法。通過配置<password-encode>來指定,然后在<user-service>中的用戶密碼屬性,提供該算法加密后的密文形式,或者在數據庫中存放密文。
對于企業來講用戶的細節也用可能存放在LDAP信息庫中,因此S-security也支持訪問LDAP驗證用戶,同樣我們配置一個<ldap-user-service>標簽,定義從LDAP中搜索用戶的方法,大部分情況下我們需要指定加密的算法,這個和LDAP中的一致。實例如下:
?<password-encoder?hash="{sha}"/>
? ? ?<ldap-user-service?server-ref="ldapServer"?????????????user-search-filter="uid={0}"?user-search-base="ou=people"
????????????group-search-filter="member={0}"?group-search-base="ou=groups"/>
? 如果數據庫或者LDAP是遠程的,則對請求的響應會有影響,S-security提供了緩存服務的緩存實現。直接加上一個cache-ref屬性就可以了。
?
6.訪問控制策略
? ACL(access control list),當一個用戶視圖訪問應用中的資源時,應用必須根據acl決定哪些資源可以訪問,哪些不可訪問。在S-security中,訪問控制決策由訪問決策管理器作出,決策管理器必須實現AccessDecisionManager接口,可隨意實現這個接口創建訪問決策管理器,當時S-security自帶3種基于投票的訪問決策管理器:
AffirmativeBased: 至少一個投票者投票贊成授予權限
ConsensusBased: 投票者一致贊成授予權限
UnanimousBased: 所有投票者贊成或者棄權(沒有拒絕訪問的投票者)?
每個投票者都必須實現AccessDecisionVoter接口,投票者可以投票贊成授權、棄權訪問資源。投票的結果由AccessDecisionVoter接口中定義的ACCESS_GRANTED,ACCESS_DENIED和ACCESS_ABSTAIN常量表示。S-security自動配置一個AffirmativeBased訪問決策控制器,配置如下兩個投票者:
RoleVoter:根據用戶角色對訪問控制決策投票。它只處理以ROLE_前綴開始的訪問屬性,但是這個前綴可以定制。如果沒有這樣的訪問屬性,它會棄權。
AuthenticatedVoter:根據用戶驗證級別對訪問控制決策投票。它只處理IS_AUTHENTICATED_FULLY,IS_AUTHENTICATED_REMEMBERED和IS_AUTHENTICATED_ANONYMOUSLY訪問屬性。如果用戶的驗證級別高于所需的屬性則投票授權。
?如果自定義投票者需要實現AccessDecisionVoter接口,自定義屬性前綴,沒有這樣前綴的訪問屬性則會投棄權票。接下來我們就需要把這個自定義的投票者和系統默認的兩個投票者配置在一起,包含在AffirmativeBased下,或者其他決策管理器下。?
?
7.方法調用的安全?
? S-security還可以讓你在服務層的方法調用上安全控制,你可以實現方法上的細粒度的控制,通過在Bean中其納入一個<security:intercept-methods>元素來實現,也可配置全局的<global-method-security>元素,加強與AspectJ切入點表達式匹配的多個方法的安全。還可通過加上@Secured注解,然后在<global-method-security>中啟用他們。如下:
<bean?id="xyzService"?class="xx.yy.zz.xyzService">
<security:intercept-methods?access-decision-manager-ref="accessDecisionManager">????????????????????<security:protect?method="xx.yy.zz.xyzService.xyz"?access="ROLE_ADMIN,ROLE_USER"/>
????????????</security:intercept-methods>
? ? ?</bean>?
還可在<global-method-security>中定義全局切入點,使用AspectJ切入點表達式加強方法安全,如:
<global-method-security?access-decision-manager-ref="accessDecisionManager">
<protect-pointcut?expression="execution(?*?xx.yy.zz.*Service.xyz*(..))"?access="ROLE_ADMIN,ROLE_USER"/>? ? ?</global-method-security>?
? 還可使用注解的形式,在方法的前加上@Secured注解,并且可以用注解值指定訪問屬性,類型為String[],如:
@Secured({"ROLE_ADMIN","ROLE_USER"})?
public void xyz(){....}?
當然這種方法需要在配置中啟用注解,如下:
<global-method-security secured-annotations="enabled" access-decision-manager-ref="accessDecisionManager">?
?
8.視圖控制的安全
? 在Web應用中,有時候我們想控制具有不同權限的用戶的顯示視圖,S-security也提供了該服務的支持。S-security有一個jsp的標簽庫,用于處理Jsp視圖中的安全控制。使用時首先將標簽庫引入 ?<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<security:authentication>標記暴露當前用戶的Authentication對象,供你顯示其屬性。通過<security:authorize>與SpEL的配合有條件顯示不同內容,如:
<security:authorize?ifAllGranted="ROLE_ADMIN,ROLE_USER">
<tr><td>Author</td><td>${message.author}</td></tr>? ? ?</security:authorize>?
? ?
9.領域對象的安全(ACL)
? 有時候如果更加復雜的安全需求,需要在不同對象上進行安全控制,S-security也提供了該服務的支持。Spring提供ACL包含一個與領域對象關聯的對象標識,同時保存多個訪問控制項。其含有兩個核心部分:
權限:ACE的權限由一個特別的位屏蔽代表,每位的值用于特定類型的權限,BasePermission預先定義了5中基本權限的常量值READ(0)、WRITE(1)、CREATE(2)、DELETE(3)、ADMINISTRATION(4),括號里代表位。
安全標識:每個ACE包含特定的SID的權限,其可以是一個與權限關聯的角色或者授權。
S-security還定義了用于讀取和維護模型的API,并為這些API提供了高性能的JDBC實現。在S-security中有兩個定義ACL服務操作的接口,AclService和MutableAclService,后面是前者的子接口,定義用于創建、更新和刪除Acl操作。配置如下:
?<bean?id="aclService"?class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
<constructor-arg?ref="dataSource"?/>????????????<constructor-arg?ref="lookupStrategy"/>
????????????<constructor-arg?ref="aclCache"/>
????????????<property?name="sidIdentityQuery"?value="values?identity_val_local()"/>
? ? ?</bean>
? 第二個參數sidIdentityQuery是進行ACL服務查找的策略。S-security自帶的唯一實現是BasicLookupStrategy,它使用標準和兼容的SQL語句進行基本查找。如果需要其他的查找性能,可以實現LookupStrategy接口創建自己的查找策略。
在我們的Service和Dao中,可以用上述的Acl服務,為對象維護acl。如下所示:
?...
ObjectIdentity?oid?=?new?ObjectIdentityImpl(Message.class,message.getId());MutableAcl?acl?=?mutableAclService.createAcl(oid);
acl.insertAce(0,BasePermission.ADMINISTRATION,new?PrincipalSid(message.getAuthor()),true);
acl.insertAce(1,BasePermission.DELETE,new?GrantedAuthoritySid("ROLE_ADMIN"),true);
acl.insertAce(2,BasePermission.READ,new?GrantedAuthoritySid("ROLE_USER"),true);
mutableAclService.updateAcl(acl);
? ? ?...
? 上述的定義則是允許message的作者管理;允許具有ADMIN角色的用戶刪除它;允許USER角色的用戶閱讀它。
我們已經可將aclService定義好了,并且已經注入進Spring相關的Service層Bean中。下面我們便可以根據ACL控制涉及該對象方法的安全控制了。S-security自己提供了acl投票者類 AclEntryVoter類,同時也允許自定義基于ACL的投票者。AclEntryVoter使用時需指定processDomainObjectClass屬性,就是指明我們對哪個類的對象添加了ACL服務。該投票者類不可為基于http的訪問決策投票,即我們不能直接將其包含在全局訪問決策管理器中。但可使用如下方式:
<global-method-security secured-annotation="enabled" access-decision-manager-ref="aclAccessDecisionManager"/>
同樣S-security也支持tag的方式,有條件顯示相應的視圖,配合使用 <security:accesscontrollist>標簽和SpEL。
?如果用戶調用了方法等返回了對象,我們也要進行ACL控制的話。可使用AclEntryAfterInvocationProvider和AclEntryAfterInvocationCollectionFilteringProvider實例,前者如果不具有權限會拋出異常阻止返回,后者會進行過濾結果。在Bean的配置中嵌入<customafter-invocation-provider>元素,就能在S-security中注冊一個自定義后調用提供者。
?
轉載于:https://www.cnblogs.com/kingcucumber/p/2888621.html
總結
以上是生活随笔為你收集整理的Spring3之Security的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux Mysql 1130错误解决
- 下一篇: Hibernate + MySQL中文乱