1.spring security初體驗
applicationContext.xml
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"> <http auto-config='true'> <intercept-url pattern="/**" access="ROLE_USER" /> </http> <authentication-provider> <user-service> <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" /> <user name="bob" password="bobspassword" authorities="ROLE_USER" /> </user-service> </authentication-provider> </beans:beans>
web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <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> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <!-- <param-value>classpath*:applicationContext.xml</param-value> --> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
auto-config屬性其實是<form-login/>,<http-basic/>,<logout/>的縮寫.
沒配置登錄頁面的情況下,spring自動生成一個.
2.指定自己的登錄頁面以及跳轉規則
<http> <intercept-url pattern='/login.htm*' filters='none'/> <intercept-url pattern='/**' access='ROLE_USER' /> <form-login login-page='/login.htm' default-target-url='/home.htm' always-use-default-target='true' /> </http>
<intercept-url pattern='/login.htm*' filters='none'/>這個標籤是把驗證排除在外。因爲這是一個登錄頁面。
而form-login標籤的login-page則指定遇到受限資源需要進行登錄時候的頁面.
default-target-url指定了從登錄頁面登錄後進行跳轉的頁面
always-use-default-target這個屬性表示登錄成功後強制跳轉到default-target-url這個地址。默認情況下如果是從首先頁面過來登錄的,那麼跳轉是跳轉回受限頁面。
3.其他的驗證方式.
LDAP驗證
<authentication-provider user-service-ref='myUserDetailsService'/>
DATABASE驗證
<authentication-provider> <jdbc-user-service data-source-ref="securityDataSource"/> </authentication-provider>
或者
<authentication-provider user-service-ref='myUserDetailsService'/> <beans:bean id="myUserDetailsService" class="org.springframework.security.userdetails.jdbc.JdbcDaoImpl"> <beans:property name="dataSource" ref="dataSource"/> </beans:bean>
4.密碼的編碼器配置
<authentication-provider> <password-encoder hash="sha"/> <user-service> <user name="jimi" password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f" authorities="ROLE_USER, ROLE_ADMIN" /> <user name="bob" password="4e7421b1b8765d8f9406d87e7cc6aa784c4ab97f" authorities="ROLE_USER" /> </user-service> </authentication-provider>
另外還以爲密碼配置種子(鹽值)
<password-encoder hash="sha"> <salt-source user-property="username"/> </password-encoder>
還可以通過password-encoder的ref屬性,指定一個自定義的密碼編碼器bean。 這應該包含application context中一個bean的名字,它應該是Spring Security的PasswordEncoder接口的一個實例。
5.對HTPPS的處理
<http> <intercept-url pattern="/secure/**" access="ROLE_USER" requires-channel="https"/> <intercept-url pattern="/**" access="ROLE_USER" requires-channel="any"/> ... </http>
當用戶用http訪問需要https的訪問驗證時可以通過requires-channel屬性來進行跳轉.
requires-channel共有三個值:http,https,any。 any表示http和https都可以。
如果使用了非默認的http和https的端口號,那麼添加port-mappings即可
<http> ... <port-mappings> <port-mapping http="9080" https="9443"/> </port-mappings> </http>
6.限制用戶的登錄(單次登錄)
在web.xml中添加監聽器
<listener> <listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class> </listener>
然後再配spring置中添加
<http> ... <concurrent-session-control max-sessions="1" /> </http>
這種做法是在第二次登陸時,第一登錄就失效了。
如果想禁止第二次登陸,那麼可以設置exception-if-maximum-exceeded.
<http> ... <concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="true"/> </http>
字面上不難理解,第二次登陸就拋出異常,這樣就防止了重複登錄
7.OpenID登錄
命名空間支持OpenID登錄,替代普通的表單登錄,或作爲一種附加功能,只需要進行簡單的修改:
<http> <intercept-url pattern="/**" access="ROLE_USER" /> <openid-login /> </http>
你應該註冊一個OpenID供應器(比如myopenid.com),然後把用戶信息添加到你的內存<user-service>中:
<user name="http://jimi.hendrix.myopenid.com/" password="notused" authorities="ROLE_USER" />
你應該可以使用myopenid.com網站登錄來進行驗證了。
8.添加自己的過濾器
添加你自己的filter
如果你以前使用過Spring Security,你就應該知道這個框架裏維護了一個過濾器鏈,來提供服務。 你也許想把你自己的過濾器添加到鏈條的特定位置,或者使用一個Spring Security的過濾器,這個過濾器現在還沒有在命名空間配置中進行支持(比如CAS)。 或者你想要使用一個特定版本的標準命名空間過濾器,比如<form-login>創建的AuthenticationProcessingFilter,從而獲得一些額外的配置選項的優勢,這些可以通過直接配置bean獲得。 你如何在命名空間配置裏實現這些功能呢?過濾器鏈現在已經不能直接看到了。
過濾器順序在使用命名空間的時候是被嚴格執行的。 每個Spring Security過濾器都實現了Spring的Ordered接口,這些通過命名空間穿件的過濾器在初始化的時候就預先被排好序了。 標準的過濾器在命名空間裏都有自己的假名,有關創建過濾器的過濾器,假名和命名空間元素,屬性可以在Table 2.1, “標準過濾器假名和順序”中找到。
假名 | 過濾器累 | 命名空間元素或屬性 |
CHANNEL_FILTER | ChannelProcessingFilter | http/intercept-url |
CONCURRENT_SESSION_FILTER | ConcurrentSessionFilter | http/concurrent-session-control |
SESSION_CONTEXT_INTEGRATION_FILTER | HttpSessionContextIntegrationFilter | http |
LOGOUT_FILTER | LogoutFilter | http/logout |
X509_FILTER | X509PreAuthenticatedProcessigFilter | http/x509 |
PRE_AUTH_FILTER | AstractPreAuthenticatedProcessingFilter | Subclasses N/A |
CAS_PROCESSING_FILTER | CasProcessingFilter | N/A |
AUTHENTICATION_PROCESSING_FILTER | AuthenticationProcessingFilter | http/form-login |
BASIC_PROCESSING_FILTER | BasicProcessingFilter | http/http-basic |
SERVLET_API_SUPPORT_FILTER | SecurityContextHolderAwareRequestFilter |
http/@servlet-api-provision |
REMEMBER_ME_FILTER | RememberMeProcessingFilter | http/remember-me |
ANONYMOUS_FILTER | AnonymousProcessingFilter | http/anonymous |
EXCEPTION_TRANSLATION_FILTER | ExceptionTranslationFilter | http |
NTLM_FILTER | NtlmProcessingFilter | N/A |
FILTER_SECURITY_INTERCEPTOR | FilterSecurityInterceptor |
http |
SWITCH_USER_FILTER SwitchUserProcessingFilter N/A
你可以把你自己的過濾器添加到隊列中,使用custom-filter元素,使用這些名字中的一個,來指定你的過濾器應該出現的位置:
<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"> <custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/> </beans:bean>
你還可以使用after 或 before屬性,如果你想把你的過濾器添加到隊列中另一個過濾器的前面或後面。 可以分別在position屬性使用"FIRST" 或 "LAST"來指定你想讓你的過濾器出現在隊列元素的前面或後面。
避免過濾器位置發生衝突
如果你插入了一個自定義的過濾器,而這個過濾器可能與命名空間自己創建的標準過濾器放在同一個位置上,這樣首要的是你不要錯誤包含命名空間的版本信息。 避免使用auto-config屬性,然後刪除所有會創建你希望替換的過濾器的元素。
注意,你不能替換那些<http>元素自己使用而創建出的過濾器,比如HttpSessionContextIntegrationFilter, ExceptionTranslationFilter 或 FilterSecurityInterceptor。
如果你替換了一個命名空間的過濾器,而這個過濾器需要一個驗證入口點(比如,認證過程是通過一個未通過驗證的用戶訪問受保護資源的嘗試來觸發的),你將也需要添加一個自定義的入口點bean。
9.防止session固定攻擊。
<http>中的session-fixation-protection屬性配置可以防止這種攻擊。
它有三個選項:
a.migrateSession - 創建一個新session,把原來session中所有屬性複製到新session中。這是默認值。
b.none - 什麼也不做,繼續使用原來的session。
c.newSession - 創建一個新的“乾淨的”session,不會複製session中的數據。
10.方法的保護
a.
<global-method-security secured-annotations="enabled" jsr250-annotations="enabled"/>
這個標籤用於開啓Spring Security的@Secured和JSR-250註解功能
public interface BankService {
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account readAccount(Long id);
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account[] findAccounts();
@Secured("ROLE_TELLER")
public Account post(Account account, double amount);
}
b.使用protect-pointcut來添加安全切點
<global-method-security> <protect-pointcut expression="execution(* com.mycompany.*Service.*(..))" access="ROLE_USER"/> </global-method-security>
c.使用intercept-methods來構建安全方法
<bean:bean id="target" class="com.mycompany.myapp.MyBean"> <intercept-methods> <protect method="set*" access="ROLE_ADMIN" /> <protect method="get*" access="ROLE_ADMIN,ROLE_USER" /> <protect method="doSomething" access="ROLE_USER" /> </intercept-methods> </bean:bean>
11.自定義的AccessDecisionManager
方法安全的配置
<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean"> ... </global-method-security>
web安全的配置
<http access-decision-manager-ref="myAccessDecisionManagerBean"> ... </http>
12.默認的驗證管理器
如果你在命名空間中使用了HTTP或方法安全,你不能使用自定義的AuthenticationManager.
ProviderManager註冊另外的AuthenticationProvider bean,你可以使用<custom-authentication-provider>元素實現
<bean id="casAuthenticationProvider" class="org.springframework.security.providers.cas.CasAuthenticationProvider"> <security:custom-authentication-provider /> ... </bean>
另一個常見的需求是,上下文中的另一個bean可能需要引用AuthenticationManager。 這裏有一個特殊的元素,可以讓你爲AuthenticationManager註冊一個別名,然後你可以application context的其他地方使用這個名字。
<security:authentication-manager alias="authenticationManager"/> <bean id="customizedFormLoginFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter"> <security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/> <property name="authenticationManager" ref="authenticationManager"/> ... </bean>
13.從任意位置獲取用戶名密碼等信息.
Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (obj instanceof UserDetails) {
String username = ((UserDetails)obj).getUsername();
} else {
String username = obj.toString();
}