下面是servlet的加載順序。
web.xml 中 對象的加載順序爲:先 listener >> filter >> servlet >> spring
在spring security demo例子中,所有的配置文件有幾個:
1、web.xml 這個是web項目的標準配置文件。
2、applicationContext-security.xml 這個是和spring security相關的配置文件
3、applicationContext-business.xml 這個是和spring security相關的配置文件
4、logback.xml 這個是和日誌相關的配置文件
5、bank-servlet.xml 這個是spring mvc相關的配置文件。
首先分析web.xml配置文件。原文就不在這裏貼出來了,只對重點內容進行分析。
spring security 過濾器配置爲:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
後研究了源碼,核心代碼如下:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Lazily initialize the delegate if necessary.
Filter delegateToUse = null;
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
}
this.delegate = initDelegate(wac);
}
delegateToUse = this.delegate;
}
// Let the delegate perform the actual doFilter operation.
invokeDelegate(delegateToUse, request, response, filterChain);
}
protected void invokeDelegate(
Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
delegate.doFilter(request, response, filterChain);
}
這裏面用到了WebApplicationContext,這也是我上篇轉載WebApplicationContext 介紹的原因。
WebApplicationContext 在web.xml的配置爲:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
通過WebApplicationContext加載applicationContext-security.xml、applicationContext-business.xml 兩個配置文件得到spring security的所有配置。
從這兩段代碼中可以看到,spring security的權限核心就是過濾器,他將 HTTP 請求委託給 Spring 應用程序上下文中的一個 Bean . 被委託的 Bean 實現了 javax.servlet.Fitler 接口, 但它需要受 Spring IOC 容器管理, 而不是直接在 web.xml 中配置*.默認情況下, DelegatingFilterProxy 會把 HTTP 請求委託給和它的 <filter-name> 屬性相同的 Bean 上(也可以在 targetBeanName 初始參數中覆蓋該 Bean 的名字).
SpringSecurity 在 web 服務器加載當前 web 應用時配置一個名稱爲 springSecurityFilterChain 的過濾器鏈(SpringSecurity 即通過該過濾器鏈爲 web 應用提供安全服務), 所以 <filter-name> 應該使用這個名字.
Spring Security的web架構是完全基於標準的servlet過濾器的。它沒有在內部使用servlet或任何其他基於servlet的框架(比如spring mvc),所以它沒有與任何特定的web技術強行關聯。 它只管處理HttpServletRequest 和HttpServletResponse,不關心請求時來自瀏覽器,web服務客戶端,HttpInvoker還是一個AJAX應用。
Spring Security維護了一個過濾器鏈,每個過濾器擁有特定的功能,過濾器需要服務也會對應添加和刪除。過濾器的次序是非常重要的,它們之間都有依賴關係。 如果你已經使用了命名空間配置,過濾器會自動幫你配置, 你不需要定義任何Spring Bean,但是有時候你需要完全控制Spring過濾器鏈,因爲你使用了命名空間沒有提供的特性,或者你需要使用你自己自定義的類。
這個過濾器裏沒有實現過濾器的任何邏輯。 DelegatingFilterProxy做的事情是代理Filter的方法,從application context裏獲得bean。這讓bean可以獲得spring web application context的生命週期支持,使配置較爲輕便。 bean必須實現javax.servlet.Filter接口,它必須和filter-name裏定義的名稱是一樣的。
下表列出了這些安全過濾器的名稱作用以及它們在系統中的執行順序:
過濾器 |
作 用 |
通道處理過濾器 |
確保請求是在安全通道(HTTP和HTTPS)之上傳輸的 |
認證處理過濾器 |
接受認證請求,並將它們轉交給認證管理器進行身份驗證 |
CAS處理過濾器 |
接受CAS服務票據,驗證Yale CAS(單點登錄)是否已經對用戶進行了認證 |
HTTP基本授權過濾器 |
處理使用HTTP基本認證的身份驗證請求 |
集成過濾器 |
處理認證信息在請求間的存儲(比如在HTTP會話中) |
安全強制過濾器 |
確保用戶己經認證,並且滿足訪問一個受保護Web資源的權限需求 |
每個Spring Security過濾器都實現了Spring的Ordered接口, 這些過濾器在初始化的時候先被排好序了。 標準的過濾器在命名空間裏都有自己的假名:
spring security 默認的過濾器是放在web命名空間http://www.springframework.org/schema/security中的。
深入到spring-security-3.1.xsd中可以看到如下配置。
<xs:simpleType name="named-security-filter">
<xs:restriction base="xs:token">
<xs:enumeration value="FIRST"/>
<xs:enumeration value="CHANNEL_FILTER"/>
<xs:enumeration value="CONCURRENT_SESSION_FILTER"/>
<xs:enumeration value="SECURITY_CONTEXT_FILTER"/>
<xs:enumeration value="LOGOUT_FILTER"/>
<xs:enumeration value="X509_FILTER"/>
<xs:enumeration value="PRE_AUTH_FILTER"/>
<xs:enumeration value="CAS_FILTER"/>
<xs:enumeration value="FORM_LOGIN_FILTER"/>
<xs:enumeration value="OPENID_FILTER"/>
<xs:enumeration value="BASIC_AUTH_FILTER"/>
<xs:enumeration value="SERVLET_API_SUPPORT_FILTER"/>
<xs:enumeration value="REMEMBER_ME_FILTER"/>
<xs:enumeration value="ANONYMOUS_FILTER"/>
<xs:enumeration value="EXCEPTION_TRANSLATION_FILTER"/>
<xs:enumeration value="SESSION_MANAGEMENT_FILTER"/>
<xs:enumeration value="FILTER_SECURITY_INTERCEPTOR"/>
<xs:enumeration value="SWITCH_USER_FILTER"/>
<xs:enumeration value="LAST"/>
</xs:restriction>
</xs:simpleType>
標準過濾器別名和順序 Java代碼
Alias Filter Class
CHANNEL_FILTER ChannelProcessingFilter
CONCURRENT_SESSION_FILTER ConcurrentSessionFilter
SESSION_CONTEXT_INTEGRATION_FILTER HttpSessionContextIntegrationFilter
LOGOUT_FILTER LogoutFilter
X509_FILTER X509PreAuthenticatedProcessigFilter
PRE_AUTH_FILTER Subclass of AstractPreAuthenticatedProcessingFilter
CAS_PROCESSING_FILTER CasProcessingFilter
AUTHENTICATION_PROCESSING_FILTER AuthenticationProcessingFilter
BASIC_PROCESSING_FILTER BasicProcessingFilter
SERVLET_API_SUPPORT_FILTER classname
REMEMBER_ME_FILTER RememberMeProcessingFilter
ANONYMOUS_FILTER AnonymousProcessingFilter
EXCEPTION_TRANSLATION_FILTER ExceptionTranslationFilter
NTLM_FILTER NtlmProcessingFilter
FILTER_SECURITY_INTERCEPTOR FilterSecurityInterceptor
SWITCH_USER_FILTER SwitchUserProcessingFilter
控制同一個用戶是否可以同時進行多次登錄:
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
對應到applicationContext-security.xml的配置爲:
<sec:session-management invalid-session-url="/timeout.jsp">
<sec:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</sec:session-management>
HttpSessionEventPublisher類實現javax.servlet.http.HttpSessionListener接口,在Session被創建的時候通過調用ApplicationContext的publishEvent(ApplicationEvent event)發佈HttpSessionCreatedEvent類型的事件,HttpSessionCreatedEvent類繼承自org.springframework.context.ApplicationEvent類的子類 HttpSessionApplicationEvent抽象類。
下面是spring mvc的標準配置:
<servlet>
<servlet-name>bank</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>bank</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
在工程的applicationContext-security.xml的關鍵配置爲:
<!--這個元素用來在你的應用程序中啓用基於安全的註解,可以使用新的基於表達式的預付-->
<sec:global-method-security pre-post-annotations="enabled" />
<!--繞過過濾器鏈的配置-->
<sec:http pattern="/static/**" security="none"/>
<sec:http use-expressions="true">
<sec:intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')"/>
<sec:intercept-url pattern="/secure/**" access="isAuthenticated()" />
<sec:intercept-url pattern="/**" access="permitAll" />
<!--默認登錄頁,如果要自定義配置爲<s:form-login login-page="/login.action" default-target-url="/main.action" authentication-failure-url="/login.action?error=true" />-->
<sec:form-login />
<sec:logout logout-success-url="/loggedout.jsp" delete-cookies="JSESSIONID"/>
<sec:remember-me />
<!--上面解釋過了是爲了控制同一個用戶是否可以同時進行多次登錄:-->
<sec:session-management invalid-session-url="/timeout.jsp">
<sec:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</sec:session-management>
<!--這裏可以配置自定義的過濾器,放在LAST之後<sec:custom-filter after="LAST" ref="resourceSecurityInterceptor" />-->
</sec:http>
下面配置用戶認證的地方:
<sec:authentication-manager>
<!--可以用自定義userDetailsService來進行認證
<sec:authentication-provider user-service-ref="userDetailsService">
<sec:password-encoder hash="plaintext" />
</sec:authentication-provider>
-->
<!--可以用數據庫進行配置,這樣要求你的數據庫表要符合一定的要求-->
<sec:authentication-provider>
<sec:password-encoder hash="md5"/>
<sec:jdbc-user-service data-source-ref="dataSource"/>
</sec:authentication-provider>
-->
<sec:authentication-provider>
<!--也可以用標準算法做加密例子如:<sec:password-encoder hash="md5"/>-->
<sec:password-encoder ref="encoder"/>
<sec:user-service>
<sec:user name="rod" password="4efe081594ce25ee4efd9f7067f7f678a347bccf2de201f3adf2a3eb544850b465b4e51cdc3fcdde" authorities="supervisor, user, teller" />
<sec:user name="dianne" password="957ea522524a41cbfb649a3e293d56268f840fd5b661b499b07858bc020d6d223f912e3ab303b00f" authorities="user,teller" />
<sec:user name="scott" password="fb1f9e48058d30dc21c35ab4cf895e2a80f2f03fac549b51be637196dfb6b2b7276a89c65e38b7a1" authorities="user" />
<sec:user name="peter" password="e175750688deee19d7179d444bfaf92129f4eea8b4503d83eb8f92a7dd9cda5fbae73638c913e420" authorities="user" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
加密方式配置
<beans:bean id="encoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"/>
以上就是與spring security 相關的配置。