javascript
spring安全_Spring安全–幕后
spring安全
安全任務(例如,用戶身份驗證和用戶查看應用程序資源的授權)通常由應用程序服務器處理。 可以將這些任務委托給Spring安全性流程,以減輕應用程序服務器處理這些任務的負擔。 Spring安全性基本上通過實現標準javax.servlet.Filter來處理這些任務。 為了在應用程序中初始化Spring安全性,您需要在web.xml中聲明以下過濾器:
現在,這個過濾器(springSecurityFilterChain)僅將請求委托給Spring安全框架,在此框架中定義的安全任務將由在應用程序上下文中定義的安全過濾器處理。 那么這是怎么發生的呢?
在DelegatingFilterProxy(javax.servlet.Filter的實現)的doFilter方法中,將檢查spring應用程序上下文中是否有名為“ springSecurityFilterChain”的bean。 這個'springSecurityFilterChain'bean實際上是為spring過濾器鏈定義的別名。
<alias name="filterChainProxy" alias="springSecurityFilterChain"/>因此,當在應用程序上下文中完成檢查時,它將返回filterChainProxy bean。 此過濾器鏈與javax.servlet.FilterChain的鏈不同,web.xml中定義的Java過濾器使用javax.servlet.FilterChain來調用下一個可能的過濾器(如果存在的話)或將請求傳遞給servlet / jsp。 bean filterChainProxy包含在Spring應用程序上下文中定義的安全過濾器的有序列表。 所以這是下一組問題:
1.誰初始化/定義這個filterChainProxy?
2.在Spring應用程序上下文中定義了哪些安全過濾器?
3.這些安全過濾器與web.xml中定義的普通過濾器有何不同?
現在是第一個問題,當在應用程序上下文中定義了安全名稱空間的?http?元素時,將初始化filterChainProxy。 這是?http?元素的基本結構:
<sec:http auto-config="true"><sec:intercept-url pattern="/**" access="ROLE_USER" /> </sec:http><sec:authentication-manager id="authenticationManager"><sec:authentication-provider><sec:user-service><sec:user name="admin" password="password" authorities="ROLE_USER, ROLE_ADMIN" /><sec:user name="user" password="password" authorities="ROLE_USER" /></sec:user-service></sec:authentication-provider> </sec:authentication-manager>現在,來自Spring框架的HttpSecurityBeanDefinitionParser會讀取?http?元素以在應用程序上下文中注冊filterChainProxy。 將auto-config設置為true的http元素實際上是以下內容的簡寫形式:
<sec:http><sec:form-login /><sec:http-basic /><sec:logout /> </sec:http>稍后我們將討論?http?的子元素。 因此,現在提到第二個問題,默認情況下,所有過濾器都在過濾器鏈中注冊了什么? 這是Spring文檔的答案:
?http?名稱空間塊始終創建一個SecurityContextPersistenceFilter , ExceptionTranslationFilter和FilterSecurityInterceptor 。 這些是固定的,不能用替代方法替代。
因此,默認情況下,當我們添加?http?元素時,將添加以上三個過濾器。 并且由于我們將auto-config設置為true,BasicAuthenticationFilter,LogoutFilter和UsernamePasswordAuthenticationFilter也被添加到過濾器鏈中。 現在,如果您查看任何這些過濾器的源代碼,它們也是標準的javax.servlet.Filter實現。 但是,通過在應用程序上下文而不是在web.xml中定義這些過濾器,應用程序服務器會將控件轉移到Spring以處理與安全性相關的任務。 Spring的filterChainProxy將負責鏈接將應用于請求的安全過濾器。 這回答了第三個問題。
為了更好地控制要應用于請求的安全篩選器,我們可以定義自己的FilterChainProxy實現。
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy"><sec:filter-chain-map path-type="ant"><sec:filter-chain pattern="/images/*" filters="none"/><sec:filter-chain pattern="/**" filters="securityContextFilter, logoutFilter, formLoginFilter, servletApiFilter, anonFilter, exceptionTranslator, filterSecurityInterceptor, customFilter1, customeFilter2" /></sec:filter-chain-map> </bean>從上面的xml中可以看出,我們不希望對圖像應用任何過濾器,而對于其余請求,則指定了必須應用的一系列過濾器。 因此,通常,我們按照從最小約束到最大約束的順序指定過濾器鏈。 但是通常不需要這種注冊我們自己的過濾器鏈的方法。 Spring通過?http?元素提供了多個掛鉤,通過這些掛鉤我們可以更好地控制安全性的應用方式。 因此,我們將詳細介紹所有可以通過?http?元素配置的內容。
1.身份驗證:HttpBasicAuthentication和基于表單登錄的身份驗證
2.通過ACL(訪問控制列表)的授權支持
3.注銷支持 4.匿名登錄支持 5.記住我身份驗證 6.并發會話管理
(1)身份驗證:身份驗證可以通過兩種方式處理-HttpBasicAuthentication和基于表單登錄的身份驗證。 我們將在短期內簡要討論這兩個。 在理解這些內容之前,最好對AuthenticationManager有所基礎,這是通過Spring安全性實現身份驗證的核心。 在身份驗證管理器元素內,我們定義了可用于該應用程序的所有身份驗證提供程序。 身份驗證提供程序包含UserDetailsS??ervice的實現。 Spring將用戶信息加載到UserDetailsS??ervice中,并將用戶名/密碼組合與登錄時提供的憑據進行比較。 這是UserDetailsS??ervice接口:
package org.springframework.security.core.userdetails;import org.springframework.dao.DataAccessException;/*** Core interface which loads user-specific data.* It is used throughout the framework as a user DAO and is the strategy used by the* {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider DaoAuthenticationProvider}.* The interface requires only one read-only method, which simplifies support for new data-access strategies.* @see org.springframework.security.authentication.dao.DaoAuthenticationProvider* @see UserDetails* @author Ben Alex*/ public interface UserDetailsService {/*** Locates the user based on the username. In the actual implementation, the search may possibly be case* insensitive, or case insensitive depending on how the implementation instance is configured. In this case, the* <code>UserDetails</code> object that comes back may have a username that is of a different case than what was* actually requested..** @param username the username identifying the user whose data is required.** @return a fully populated user record (never <code>null</code>)** @throws UsernameNotFoundException if the user could not be found or the user has no GrantedAuthority* @throws DataAccessException if user could not be found for a repository-specific reason*/UserDetails loadUserByUsername(String username)throws UsernameNotFoundException, DataAccessException; }Spring提供了此服務的兩個內置實現:
(a)在應用程序上下文中存儲用戶登錄名/密碼詳細信息:
當應用程序的用戶很少時,這非常適合。 可以如下初始化:
<sec:authentication-manager id="authenticationManager"><sec:authentication-provider><sec:user-service><sec:user name="admin" password="password" authorities="ROLE_ADMIN,ROLE_USER"/><sec:user name="user" password="password" authorities="ROLE_USER"/></sec:user-service></sec:authentication-provider> </sec:authentication-manager>?authentication-provider?標記對應于DaoAuthenticationProvider,它實際上調用提供的UserDetailsS??ervice的實現。 在這種情況下,我們將直接以XML提供用戶名和密碼。 當應用程序的用戶群很大時,我們希望將信息存儲在數據庫中。
為?user-service?初始化的對應的bean是org.springframework.security.core.userdetails.memory.InMemoryDaoImpl
(b)將用戶詳細信息存儲在數據庫中:這是初始化它的方式。
<sec:authentication-manager id="authenticationManager"><sec:authentication-provider><sec:jdbc-user-service data-source-ref="dataSource" /></sec:authentication-provider> </sec:authentication-manager>Spring中的相應類是org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl。 如果查看此類,則可以發現用戶名和密碼存儲在users表中,可以分配給用戶的角色存儲在Authoritys表中。 稍后我們將討論角色。 這些是此類從數據庫中獲取用戶憑據和權限的查詢:
-- Fetch user credentials: select username,password,enabled from users where username = ? -- Fetch user authorities: select username,authority from authorities where username = ?現在假設您有一個舊數據庫,您的用戶詳細信息存儲在其他表中,然后我們可以配置Spring為獲取用戶憑據和權限而執行的獲取查詢。 假設我有一個成員表,其中包含ID,用戶名,密碼字段,以及角色表,其中包含用戶名,角色字段。 這是我們必須配置的方式:
<sec:authentication-manager id="authenticationManager"><sec:authentication-provider><!-- TBD <password-encoder hash="md5"/> --><sec:jdbc-user-service id="userDetailsService" data-source-ref="dataSource" users-by-username-query="SELECT username, password, true as enabledFROM MEMBERWHERE username=?"authorities-by-username-query="SELECT member.username, role.role as authoritiesFROM ROLE role, MEMBER memberWHERE role.member_id=member.id and member.username=?"/></sec:authentication-provider> </sec:authentication-manager>現在介紹執行身份驗證的方法:
HttpBasicAuthentication:可以如下配置:
<sec:http auto-config="true"><sec:http-basic /> </sec:http>默認情況下,啟用此選項后,瀏覽器通常會顯示一個登錄對話框供用戶登錄。 代替登錄對話框,我們可以配置它以顯示特定的登錄頁面。 這種身份驗證是在超文本傳輸??協議標準中正式定義的。 登錄憑據(已編碼為base 64)在Authentication http標頭下發送到服務器。 但是它有它自己的缺點。 最大的問題與注銷服務器有關。 大多數瀏覽器傾向于緩存會話,不同的用戶無法通過刷新瀏覽器重新登錄。 定義?http-basic?實際上在幕后定義了BasicAuthenticationFilter過濾器。 認證成功后,Authentication對象將被放入Spring securityContext中。 可以通過類SecurityContextHolder訪問安全上下文。 這是BasicAuthenticationFilter bean聲明的樣子:
<sec:custom-filter position="BASIC_AUTH_FILTER" ref="basicAuthenticationFilter" /><bean id="basicAuthenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter"><property name="authenticationManager" ref="authenticationManager"/><property name="authenticationEntryPoint" ref="authenticationEntryPoint"/> </bean><bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"><property name="loginFormUrl" value="/login.jsp"/> </bean>有關過濾器位置的更多詳細信息,請參閱枚舉org.springframework.security.config.http.SecurityFilters
基于表單登錄的身份驗證:這是我們啟用它的方式:
<sec:form-login login-page="/login.jsp"/>但是Spring提供了多個鉤子。 屬性default-target-url指定登錄頁面在用戶通過身份驗證后應該進入的位置,而authentication-failure-url定義在身份驗證失敗時用戶應該進入的頁面。
<sec:form-login login-page="/login.jsp" default-target-url="/app/messagePost" authentication-failure-url="/login.jsp?error=true"/>下一組屬性是: 始終使用默認目標,身份驗證成功處理程序引用和身份驗證失敗處理程序引用 。 身份驗證成功時,將調用authentication-success-handler-ref , 身份驗證失敗時,將調用authentication-failure-handler-ref 。 這是AuthenticationSuccessHandler和AuthenticationFailureHandler的接口。
/*** Strategy used to handle a successful user authentication.* <p>* Implementations can do whatever they want but typical behaviour would be to control the navigation to the* subsequent destination (using a redirect or a forward). For example, after a user has logged in by submitting a* login form, the application needs to decide where they should be redirected to afterwards* (see {@link AbstractAuthenticationProcessingFilter} and subclasses). Other logic may also be included if required.** @author Luke Taylor* @since 3.0*/ public interface AuthenticationSuccessHandler {/*** Called when a user has been successfully authenticated.** @param request the request which caused the successful authentication* @param response the response* @param authentication the <tt>Authentication</tt> object which was created during the authentication process.*/void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException, ServletException; }/*** Strategy used to handle a failed authentication attempt.* <p>* Typical behaviour might be to redirect the user to the authentication page (in the case of a form login) to* allow them to try again. More sophisticated logic might be implemented depending on the type of the exception.* For example, a {@link CredentialsExpiredException} might cause a redirect to a web controller which allowed the* user to change their password.** @author Luke Taylor* @since 3.0*/ public interface AuthenticationFailureHandler {/*** Called when an authentication attempt fails.* @param request the request during which the authentication attempt occurred.* @param response the response.* @param exception the exception which was thrown to reject the authentication request.*/void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,AuthenticationException exception) throws IOException, ServletException; }Spring有2個內置的成功處理程序實現。 SimpleUrlAuthenticationSuccessHandler和SavedRequestAwareAuthenticationSuccessHandler。 后者擴展了前者。
SavedRequestAwareAuthenticationSuccessHandler的目的是將用戶帶到他已重定向到Login頁面進行身份驗證的頁面。這是定義了form-login?元素時的默認成功處理程序。 我們也可以使用我們的自定義實現來覆蓋它。 假設我們始終希望在用戶登錄后顯示特定頁面,而不是讓他進入他之前所在的頁面,我們可以將always-use-default-target設置為true。
對于故障處理程序,還有兩種內置的實現:SimpleUrlAuthenticationFailureHandler和ExceptionMappingAuthenticationFailureHandler。 后者擴展了前者。
我們僅在SimpleUrlAuthenticationFailureHandler的情況下指定單個URL,在身份驗證失敗的情況下將用戶轉到該URL,而在ExceptionMappingAuthenticationFailureHandler的情況下,我們根據身份驗證異常的類型指定用戶將轉到的URL(org.springframework的子類.security.core.AuthenticationException)在身份驗證過程中拋出(UserDetailsS??ervice實現將拋出異常)。
同樣,在定義自定義登錄頁面時,我們將用戶名和密碼字段分別標記為j_username和j_password ,并且Submit操作將默認為j_spring_security_check 。 我們還可以配置這些字段名稱,并通過分別指定以下屬性來提交操作: 用戶名參數,密碼參數和login-processing-url 。
過濾器定義如下所示:
<sec:custom-filter position="FORM_LOGIN_FILTER" ref="formLoginFilter" /> <bean id="formLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"><property name="authenticationManager" ref="authenticationManager"/><property name="filterProcessesUrl" value="/j_spring_security_check"/><property name="usernameParameter" value="username "/><property name="passwordParameter" value="password"/><property name="authenticationSuccessHandler"><bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler "><property name="alwaysUseDefaultTargetUrl" value="true"/><property name="defaultTargetUrl" value="/success.jsp"/></bean></property><property name="authenticationFailureHandler"><!--bean class=" org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler "/--><bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler"><property name="exceptionMappings"><props><prop key="org.springframework.security.authentication.BadCredentialsException">/login/badCredentials</prop><prop key="org.springframework.security.authentication.CredentialsExpiredException">/login/credentialsExpired</prop><prop key="org.springframework.security.authentication.LockedException">/login/accountLocked</prop><prop key="org.springframework.security.authentication.DisabledException">/login/accountDisabled</prop></props></property></bean></property></bean>在表單登錄的情況下,如基本身份驗證中所述,注銷不會有任何問題。 但是缺點是用戶名和密碼在標題中以明文形式發送。 這可以通過使用加密技術對密碼進行編碼來解決。 Spring使用身份驗證提供程序中的?password-encoder?元素為此提供了內置支持。 這是我們如何配置它:
<sec:authentication-manager id="authenticationManager"><sec:authentication-provider><sec:password-encoder hash="md5"/><sec:jdbc-user-service data-source-ref="dataSource" /></sec:authentication-provider> </sec:authentication-manager>2.通過ACL進行授權支持: Spring通過?http?中的?intercept-url?支持授權。
<sec:http access-decision-manager-ref="accessDecisionManager"><sec:intercept-url pattern="/app/messageList*" access="ROLE_USER,ROLE_ANONYMOUS"/><sec:intercept-url pattern="/app/messagePost*" access="ROLE_USER"/><sec:intercept-url pattern="/app/messageDelete*" access="ROLE_ADMIN"/><sec:intercept-url pattern="/app/*" access="ROLE_USER"/><form-login login-page="/login.jsp" default-target-url="/app/messagePost" authentication-failure-url="/login.jsp?error=true"/><!-- Other settings --> </sec:http>每個intercept-url指定一個URL模式,用戶必須具有角色才能訪問與指定模式匹配的那些URL。 請注意,網址格式始終以“ *”結尾。 如果未指定“ *”,則問題是黑客可以通過僅在url中傳遞一些參數來繞過安全機制。
因此,在幕后發生的事情是當Spring將所有這些URL作為元數據傳遞給FilterSecurityInterceptor時被攔截。 因此,這是不使用?intercept-url?即可配置的方法:
<sec:custom-filter position="FILTER_SECURITY_INTERCEPTOR" ref="filterSecurityInterceptor" /> <bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"><property name="authenticationManager" ref="authenticationManager"/><property name="accessDecisionManager" ref="accessDecisionManager"/><property name="securityMetadataSource"><sec:filter-security-metadata-source lowercase-comparisons="true" request-matcher="ant" use-expressions="true"><sec:intercept-url pattern="/app/messageList*" access="ROLE_USER,ROLE_ANONYMOUS"/><sec:intercept-url pattern="/app/messagePost*" access="ROLE_USER"/><sec:intercept-url pattern="/app/messageDelete*" access="ROLE_ADMIN"/><sec:intercept-url pattern="/app/*" access="ROLE_USER"/></sec:filter-security-metadata-source></property> </bean>因此,從上面的代碼中您可以看到匿名用戶只能訪問messageList頁面,并且要查看其他任何頁面,他應該以用戶身份登錄到應用程序。 同樣,如果您仔細觀察Bean聲明,則有一個屬性'accessDecisionManager'。 這樣做的目的是什么?
實際上是由Bean做出訪問控制決策。 它必須實現AccessDecisionManager接口。 Spring提供了三個內置的訪問決策管理器。 在了解訪問決策管理器的工作原理之前,我們需要知道AccessDecisionVoter到底是什么。 AccessDecisionManager實際上由一個或多個訪問決策投票者組成。 該投票者封裝了允許/拒絕/放棄用戶查看資源的邏輯。 棄權決定或多或少類似于根本不投票,因此投票結果由AccessDecisionVoter接口中定義的ACCESS_GRANTED,ACCESS_DENIED和ACCESS_ABSTAIN常量字段表示。 我們可以定義自定義訪問決策投票者,并將其注入我們的訪問決策管理器定義中。 現在回到內置的決策管理器中,他們是:
默認情況下,將使用2個投票者初始化一個基于AffirmativeBased的訪問決策管理器:RoleVoter和AuthenticatedVoter。 如果用戶具有所需角色,RoleVoter會授予訪問權限。 但是請注意,如果投票者必須授予訪問權限,則該角色必須以“ ROLE_”前綴開頭。 但這也可以為其他前綴定制。 我們將很快看到如何做。 AuthenticatedVoter僅在用戶通過身份驗證時才授予訪問權限。 接受的身份驗證級別為IS_AUTHENTICATED_FULLY,IS_AUTHENTICATED_REMEMBERED和IS_AUTHENTICATED_ANONYMOUSLY。 假設我們要定義一個自定義投票器,并將其添加到訪問決策管理器中,我們可以這樣做:
<sec:http access-decision-manager-ref="accessDecisionManager" auto-config="true"><!-- filters declaration go here--> </sec:http><bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"><property name="decisionVoters"><list><bean class="org.springframework.security.access.vote.RoleVoter"><!-- Customize the prefix--><property name="rolePrefix" value="ROLE_"/></bean><bean class="org.springframework.security.access.vote.AuthenticatedVoter"/><bean class="com.pramati.security.voters.CustomVoter"/></list></property> </bean>3.注銷支持: Spring提供了一個處理程序來處理注銷請求。 可以如下配置:
<sec:http><!-- Other filter declarations here --><sec:logout /></sec:http>默認情況下,注銷URL映射到/ j_spring_security_logout 。 我們可以通過指定logout-url屬性來自定義該url。 同樣,當用戶注銷時,他將被帶到上下文路徑根。 如果必須將用戶重定向到其他URL,則必須通過logout-success-url進行配置。 這是您的操作方式:
<sec:logout logout-url="/j_logMeOut" logout-success-url="/app/messageList"/>如果您希望登錄頁面在不同情況下有所不同,而不是默認使用一個特定的URL,則我們必須實現LogoutSuccessHandler并將其引用到?logout?元素
<sec:logout logout-url="/j_logMeOut" success-handler-ref="customLogoutSuccessHandler"/>如果您不想使用?logout?元素,則可以按以下方法定義底層過濾器:
<sec:custom-filter position="LOGOUT_FILTER" ref="logoutFilter" /> <bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"><constructor-arg value="/pages/Security/logout.html" /><constructor-arg><list><bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/></list></constructor-arg><property name="filterProcessesUrl" value="/j_logMeOut"/> </bean>4.匿名登錄支持:默認情況下,Spring創建一個匿名角色。
因此,當您將角色指定為“ ROLE_ANONYMOUS”或“ IS_AUTHENTICATED_ANONYMOUSLY”時,任何匿名用戶都可以查看該頁面。 在AffirmativedBased訪問決策管理器中,當RoleVoter看到訪問屬性設置為“ ROLE_ANONYMOUS”時,將授予訪問權限。 同樣,如果將訪問屬性設置為“ IS_AUTHENTICATED_ANONYMOUSLY”,則AuthenticatedVoter會授予訪問權限。
假設要為匿名用戶分配其他角色名稱,則可以按如下方式覆蓋默認配置:
<sec:http><sec:intercept-url pattern="/login.jsp*" filters="none"/><sec:intercept-url pattern="/*" access="ROLE_USER"/><!-- Defines a custom role in place of ROLE_ANONYMOUS. ROLE_ANONYMOUS will no more work, use ROLE_GUEST instead of it--><sec:anonymous username="guest" granted-authority="ROLE_GUEST" /> </sec:http><p style="text-align: justify;">Here is the how the underlying filter can be defined if you don't want to use ?anonymous? element:</p>1 <sec:custom-filter position="ANONYMOUS_FILTER" ref="anonymousFilter" /> <bean id="anonymousFilter" class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter" ><property name="userAttribute" value="ROLE_GUEST" /> </bean>5.記住我身份驗證:這是指網站能夠記住會話之間主體的身份。 Spring通過在成功進行交互式身份驗證后向瀏覽器發送cookie來實現此目的,該cookie的組成如下:
base64(用戶名+“:” + expirationTime +“:” + md5Hex(用戶名+“:” + expirationTime +“:”密碼+“:” +鍵))
現在,當瀏覽器向服務器發出下一個請求時,它還將與此Cookie一起發送。 現在,Spring在幕后執行以下操作:
(a)從后端檢索給定用戶名的密碼
(b)從數據庫中獲取用戶名的密碼,并計算用戶名,密碼,expirationTime和密鑰的md5Hex()并將其與Cookie中的值進行比較 (c)如果它們匹配–您已登錄! 如果不匹配,則說明您提供了偽造的Cookie,或者用戶名/密碼/密鑰之一已更改。
我們可以通過在?http?中添加元素來啟用“記住我”身份驗證。 這是我們的方法:
<sec:http><!-- Other filter declarations here --><sec:remember-me key="myAppKey"/></sec:http>通常將自動選擇UserDetailsS??ervice。 如果您的應用程序上下文中有多個,則需要指定與user-service-ref屬性一起使用的屬性,其中值是UserDetailsS??ervice bean的名稱。 需要注意的一點是,這里存在一個潛在的安全問題,因為“記住我”令牌可以被捕獲,并且由于它在到期之前一直有效而可能被濫用。 通過使用滾動令牌可以避免這種情況。 這是您可以實現基于令牌的“記住我”服務的方法:
<sec:http access-decision-manager-ref="accessDecisionManager"><!-- Other filter declarations here --><remember-me services-alias="rememberMeService" data-source-ref="dataSource"/><!-- <remember-me data-source-ref="dataSource" key="pramati"/> --></sec:http><bean id="tokenRepository" class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl"><property name="dataSource" ref="dataSource"/><property name="createTableOnStartup" value="true"/> </bean><bean id="rememberMeService" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices"><property name="userDetailsService" ref="userDetailsService"/><property name="tokenRepository" ref="tokenRepository"/> </bean>注意事項:
(a)因為在定義bean'tokenRepository'時已指定'createTableOnStartup'為true,所以將在數據庫中創建一個新表persistent_logins。 這是用于創建表的sql:
create table persistent_logins (username varchar(64) not null,series varchar(64) primary key,token varchar(64) not null,last_used timestamp not null);(b)我們不再提供自己的安全令牌。 Spring將自動生成令牌并將其放置/更新到persistent_tokens表中。 當用戶從瀏覽器訪問應用程序并通過選擇“記住我”選項登錄到應用程序時,將在此表中創建一個條目。 下次用戶從同一瀏覽器登錄時,將自動登錄,并且數據庫中的令牌值將更改為新值,但系列值保持不變。 假設用戶現在從其他瀏覽器登錄并選擇記住我,那么將為該瀏覽器創建一個新條目。 當他從該瀏覽器訪問應用程序時,隨后的更新將發生在該特定行本身上。
因此,使用這種方法的好處是,攻擊者將只能使用被盜的cookie,直到受害者用戶下次訪問該應用程序為止,而不是像以前的單令牌方法那樣在記住的cookie的整個生存期內使用它。 當受害者下一次訪問該網站時,他將使用相同的cookie。 現在,Spring將引發CookieTheftException,該異??捎糜谕ㄖ脩舭l生了盜竊。
可以使用安全鏈中的自定義過濾器來定義它,而不用使用到目前為止已使用的元素:
<sec:custom-filter position="REMEMBER_ME_FILTER" ref="rememberMeFilter" /><bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter"><property name="rememberMeServices" ref="rememberMeServices"/><property name="authenticationManager" ref="theAuthenticationManager" /> </bean><bean id="tokenRepository" class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl"><property name="dataSource" ref="dataSource"/><property name="createTableOnStartup" value="false"/> </bean><bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices"><property name="userDetailsService" ref="userDetailsService"/><property name="tokenRepository" ref="tokenRepository"/> </bean><bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.rememberme.RememberMeAuthenticationProvider"/>6.并發會話管理:假設我們不希望用戶同時從多個地方登錄到應用程序,我們必須在Spring中啟用此功能。 這是我們的方法:
<sec:http><!-- Other filter declarations here --><sec:session-management session-authentication-error-url="/login.jsp?error=alreadyLoggedin" ><sec:concurrency-control max-sessions="1" error-if-maximum-exceeded="true"expired-url="/login.jsp?error=alreadyLoggedin"/></sec:session-management> </sec:http>此外,我們還必須在web.xml中定義一個偵聽器,當用戶從應用程序注銷時,該偵聽器對于引發事件(org.springframework.security.core.session.SessionDestroyedEvent)是必需的。
<listener><listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> </listener>那么,現在幕后發生了什么? Spring如何獲得這種支持?
Spring使用的安全過濾器類似于我們一直在討論的內容。 除此之外,它還使用ApplicationEvents。 當spring看到需要并發控制時,它將維護與主體相關聯的會話列表。 映射結構看起來像(實際上在org.springframework.security.core.session.SessionRegistryImpl中定義):
ConcurrentMap<Object,Set<String>> principals =new ConcurrentHashMap<Object,Set<String>>();此處映射的鍵是User對象,該值是與他相關聯的會話ID的集合。 因此,當集合的大小大于?concurrency-control?元素中定義的最大會話的值時,將引發異常。 當Spring看到定義的并發控制元素時,SessionRegistryImpl(已定義映射)在ConcurrentSessionControlStrategy內部組成,并注入UsernamePasswordAuthenticationFilter中。 現在,隨著用戶身份驗證成功,Spring在上面討論的映射中添加了一個條目。
現在,當用戶注銷時,將在web.xml中定義偵聽器時引發SessionDestroyedEvent,如上所示。 SessionRegistryImpl偵聽此事件,并從正在維護的映射中刪除會話ID條目。 如果沒有此設置,即使用戶退出另一個會話或超時,一旦超出會話允許量,用戶將永遠無法再次登錄。 因此,這是?concurrency-control?的等效配置:
<sec:http><sec:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" /><sec:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" /><!-- Other filter declarations here --><sec:session-management session-authentication-strategy-ref="sessionAuthenticationStrategy"/> </sec:http><bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter"><property name="sessionRegistry" ref="sessionRegistry" /><property name="expiredUrl" value="/session-expired.htm" /> </bean><bean id="myAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"><property name="sessionAuthenticationStrategy" ref="sessionAuthenticationStrategy" /><property name="authenticationManager" ref="authenticationManager" /> </bean><bean id="sessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy"><constructor-arg name="sessionRegistry" ref="sessionRegistry" /><property name="maximumSessions" value="1" /> </bean><bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" /> 總結本文,本文涉及框架的基本配置和底層類,這對于理解根據我們的特定要求自定義安全性至關重要。
翻譯自: https://www.javacodegeeks.com/2013/11/spring-security-behind-the-scenes.html
spring安全
總結
以上是生活随笔為你收集整理的spring安全_Spring安全–幕后的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 老白菜u盘启动盘如何设置u盘启动快捷键大
- 下一篇: 建筑商和机械手