基本原理html
首先須要改動login.jsp,把記住個人checkbox的name修改成自定義的名稱
java
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>自定義登錄頁面</title> </head> <body> <div class="error ${param.error == true ? '' : 'hide'}"> 登錄失敗<br> ${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message} </div> <form method="post" action="${pageContext.request.contextPath}/j_spring_security_check" style="width:260px; text-align: center"> <fieldset> <legend>登錄</legend> 用戶: <input type="text" name="j_username" style="width: 150px;" value="${sessionScope['SPRING_SECURITY_LAST_USERNAME']}" /> <br/> 密碼: <input type="password" name="j_password" style="width: 150px;" /> <br/> <input type="checkbox" name="remember-me" />記住我<br/> <input type="submit" value="登錄" /> <input type="reset" value="重置" /> </fieldset> </form> </body> </html>
須要特別注意的是,這兩種方式在配置的時候都要提供一個UserDetailsService,這個東西其實就是以前配置的jdbc-user-service標籤的一個實現類,配置代碼以下:mysql
<beans:bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl"> <beans:property name="usersByUsernameQuery" value="select username,password,status as enabled from user where username = ?" /> <beans:property name="authoritiesByUsernameQuery" value="select user.username,role.name from user,role,user_role where user.id=user_role.user_id and user_role.role_id=role.id and user.username=?" /> <beans:property name="dataSource" ref="dataSource" /> </beans:bean>
說明:web
<!-- Remember-Me 對應的 Filter --> <beans:bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter"> <beans:property name="rememberMeServices" ref="rememberMeServices" /> <beans:property name="authenticationManager" ref="authenticationManager" /> </beans:bean>
這個過濾器僅僅這樣配置是不會起做用的,還要把它加入的Security的FilterChain中去,用<custom-filter ref="rememberMeFilter" position="REMEMBER_ME_FILTER"/>便可,另外這個過濾器要提供一個rememberMeServices和一個用戶認證的authenticationManager,後面這個其實就是authentication-manager所配置的東西,而前面這個須要另外配置,配置方式以下:spring
<!-- RememberMeServices 的實現 --> <beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices"> <beans:property name="userDetailsService" ref="userDetailsService" /> <beans:property name="key" value="sunny" /> <!-- 指定 request 中包含的用戶是否選擇了記住個人蔘數名 --> <beans:property name="parameter" value="remember-me" /> <beans:property name="tokenRepository"> <beans:bean class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl"> <beans:property name="dataSource" ref="dataSource"/> <!-- 是否在啓動時建立持久化 token 的數據庫表 若爲true,但數據有這個表時,會啓動失敗,提示表已存在 --> <beans:property name="createTableOnStartup" value="false"/> </beans:bean> </beans:property> </beans:bean>
<!-- 記住密碼 ,key 值需與對應的 RememberMeServices 保持一致 --> <beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider"> <beans:property name="key" value="sunny" /> </beans:bean>
同時還要將其添加到authentication-manager標籤中去sql
<!--認證管理--> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="userDetailsService"></authentication-provider> <!-- 記住密碼 --> <authentication-provider ref="rememberMeAuthenticationProvider"></authentication-provider> </authentication-manager>
最後面將rememberMeServices添加到myUsernamePasswordAuthenticationFilter中去。數據庫
<!-- 自定義登陸過濾器 --> <beans:bean id="myUsernamePasswordAuthenticationFilter" class="com.sunny.auth.MyUsernamePasswordAuthenticationFilter"> <beans:property name="filterProcessesUrl" value="/j_spring_security_check" /> <beans:property name="authenticationManager" ref="authenticationManager" /> <beans:property name="authenticationSuccessHandler" ref="loginLogAuthenticationSuccessHandler" /> <beans:property name="authenticationFailureHandler" ref="simpleUrlAuthenticationFailureHandler" /> <!-- 記住我 --> <beans:property name="rememberMeServices" ref="rememberMeServices" /> </beans:bean>
<?xml version="1.0" encoding="UTF-8"?> <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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <!-- 不須要訪問權限 --> <http pattern="/page/login.jsp" security="none"></http> <http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint"> <!-- <form-login login-page="/page/login.jsp" default-target-url="/page/admin.jsp" authentication-failure-url="/page/login.jsp?error=true" /> --> <logout invalidate-session="true" logout-success-url="/page/login.jsp" logout-url="/j_spring_security_logout" /> <!-- 自定義登陸過濾器 --> <custom-filter ref="myUsernamePasswordAuthenticationFilter" position="FORM_LOGIN_FILTER" /> <!--替換默認REMEMBER_ME_FILTER--> <custom-filter ref="rememberMeFilter" position="REMEMBER_ME_FILTER"/> <!-- 經過配置custom-filter來增長過濾器,before="FILTER_SECURITY_INTERCEPTOR"表示在SpringSecurity默認的過濾器以前執行。 --> <custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" /> </http> <!-- 登陸切入點 --> <beans:bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <beans:property name="loginFormUrl" value="/page/login.jsp"/> </beans:bean> <!-- 自定義登陸過濾器 --> <beans:bean id="myUsernamePasswordAuthenticationFilter" class="com.sunny.auth.MyUsernamePasswordAuthenticationFilter"> <beans:property name="filterProcessesUrl" value="/j_spring_security_check" /> <beans:property name="authenticationManager" ref="authenticationManager" /> <beans:property name="authenticationSuccessHandler" ref="loginLogAuthenticationSuccessHandler" /> <beans:property name="authenticationFailureHandler" ref="simpleUrlAuthenticationFailureHandler" /> <!-- 記住我 --> <beans:property name="rememberMeServices" ref="rememberMeServices" /> </beans:bean> <!-- 登陸成功 --> <beans:bean id="loginLogAuthenticationSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"> <beans:property name="defaultTargetUrl" value="/page/admin.jsp" /> </beans:bean> <!-- 登陸失敗 --> <beans:bean id="simpleUrlAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <beans:property name="defaultFailureUrl" value="/page/login.jsp" /> </beans:bean> <!-- 認證過濾器 --> <beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <!-- 用戶擁有的權限 --> <beans:property name="accessDecisionManager" ref="accessDecisionManager" /> <!-- 用戶是否擁有所請求資源的權限 --> <beans:property name="authenticationManager" ref="authenticationManager" /> <!-- 資源與權限對應關係 --> <beans:property name="securityMetadataSource" ref="securityMetadataSource" /> </beans:bean> <!-- 受權管理器 --> <beans:bean id="accessDecisionManager" class="com.sunny.auth.MyAccessDecisionManager"> </beans:bean> <!--自定義的切入點--> <beans:bean id="securityMetadataSource" class="com.sunny.auth.MyFilterInvocationSecurityMetadataSource"> <beans:property name="builder" ref="builder"/> </beans:bean> <beans:bean id="builder" class="com.sunny.auth.JdbcRequestMapBulider"> <beans:property name="dataSource" ref="dataSource" /> <beans:property name="resourceQuery" value="select re.res_string,r.name from role r,resc re,resc_role rr where r.id=rr.role_id and re.id=rr.resc_id" /> </beans:bean> <!--認證管理--> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="userDetailsService"></authentication-provider> <!-- 記住密碼 --> <authentication-provider ref="rememberMeAuthenticationProvider"></authentication-provider> </authentication-manager> <!-- Remember-Me 對應的 Filter --> <beans:bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter"> <beans:property name="rememberMeServices" ref="rememberMeServices" /> <beans:property name="authenticationManager" ref="authenticationManager" /> </beans:bean> <!-- RememberMeServices 的實現 --> <beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices"> <beans:property name="userDetailsService" ref="userDetailsService" /> <beans:property name="key" value="sunny" /> <!-- 指定 request 中包含的用戶是否選擇了記住個人蔘數名 --> <beans:property name="parameter" value="remember-me" /> <beans:property name="tokenRepository"> <beans:bean class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl"> <beans:property name="dataSource" ref="dataSource"/> <!-- 是否在啓動時建立持久化 token 的數據庫表 若爲true,但數據有這個表時,會啓動失敗,提示表已存在 --> <beans:property name="createTableOnStartup" value="false"/> </beans:bean> </beans:property> </beans:bean> <!-- 記住密碼 ,key 值需與對應的 RememberMeServices 保持一致 --> <beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider"> <beans:property name="key" value="sunny" /> </beans:bean> <beans:bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl"> <beans:property name="usersByUsernameQuery" value="select username,password,status as enabled from user where username = ?" /> <beans:property name="authoritiesByUsernameQuery" value="select user.username,role.name from user,role,user_role where user.id=user_role.user_id and user_role.role_id=role.id and user.username=?" /> <beans:property name="dataSource" ref="dataSource" /> </beans:bean> </beans:beans>
spring-dataSource.xml保持不變瀏覽器
<?xml version="1.0" encoding="UTF-8"?> <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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <!-- 數據源 --> <beans:bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!-- 此爲c3p0在spring中直接配置datasource c3p0是一個開源的JDBC鏈接池 --> <beans:property name="driverClass" value="com.mysql.jdbc.Driver" /> <beans:property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springsecurity?useUnicode=true&characterEncoding=UTF-8" /> <beans:property name="user" value="root" /> <beans:property name="password" value="" /> <beans:property name="maxPoolSize" value="50"></beans:property> <beans:property name="minPoolSize" value="10"></beans:property> <beans:property name="initialPoolSize" value="10"></beans:property> <beans:property name="maxIdleTime" value="25000"></beans:property> <beans:property name="acquireIncrement" value="1"></beans:property> <beans:property name="acquireRetryAttempts" value="30"></beans:property> <beans:property name="acquireRetryDelay" value="1000"></beans:property> <beans:property name="testConnectionOnCheckin" value="true"></beans:property> <beans:property name="idleConnectionTestPeriod" value="18000"></beans:property> <beans:property name="checkoutTimeout" value="5000"></beans:property> <beans:property name="automaticTestTable" value="t_c3p0"></beans:property> </beans:bean> </beans:beans>
在將這配置以前先對上面rememberService中的實現類TokenBasedRememberMeServices進行簡單的講解,該類主要是基於簡單加密 token 的一個實現類。安全
而基礎持久化方式配置的實質就是這個類不一樣,基於持久化方式配置的所用的實現類爲:PersistentTokenBasedRememberMeServices,一看名字就知道其做用,就是將token進行持久化保存起來,要保存數據相應的就是爲其制定保存的地方,這個保存的地方就是用PersistentTokenRepository來指定的,Spring Security 對此有兩種實現,InMemoryTokenRepositoryImpl 和 JdbcTokenRepositoryImpl。前者是將 token 存放在內存中的,一般用於測試,然後者是將 token 存放在數據庫中。PersistentTokenBasedRememberMeServices 默認使用的是前者,咱們能夠經過其 tokenRepository 屬性來指定使用的 PersistentTokenRepository。這例子用JdbcTokenRepositoryImpl來進行持久化保存,顯然要往數據庫保存數據,確定要有一張表,這個表security也有提供而且是固定的,sql語句爲:cookie
create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)
在數據庫中建立該表便可。
建立後的表爲:
沒勾選【記住我】時候,登錄後再退出,再訪問/page/admin.jsp的時候就要求從新登錄。同時數據庫也不會新增數據。
當勾選【記住我】在登錄後,就算退出登錄後,再訪問/page/admin.jsp也能夠不用直接訪問,同時,數據庫也會將登錄信息保存起來,比較兩次數據還能夠發現,除了用戶名沒變,其餘的數據都會由於第二次訪問而進行更新