有三中方法可以實現驗證碼的功能
第一種是自定義一個filter,放在SpringSecurity過濾器之前,在用戶登錄的時候會先經過這個filter,然后在這個filter中實現對驗證碼進行驗證的功能,這種方法不推薦,因為它已經脫離了SpringSecurity
第二種是自定義一個filter讓它繼承自UsernamePasswordAuthenticationFilter,然后重寫attemptAuthentication方法在這個方法中實現驗證碼的功能,如果驗證碼錯誤就拋出一個繼承自AuthenticationException的驗證嗎錯誤的異常比如(CaptchaException),然后這個異常就會被SpringSecurity捕獲到并將異常信息返回到前臺,這種實現起來比較簡單
~~~
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
String requestCaptcha = request.getParameter(this.getCaptchaFieldName());
String genCaptcha = (String)request.getSession().getAttribute("code");
logger.info("開始校驗驗證碼,生成的驗證碼為:"+genCaptcha+" ,輸入的驗證碼為:"+requestCaptcha);
if( !genCaptcha.equals(requestCaptcha)){
throw new CaptchaException(
this.messageSource.getMessage("AbstractUserDetailsAuthenticationProvider.badCaptcha",null,"Default",null));
}
return super.attemptAuthentication(request, response);
}
~~~
然后在配置文件中配置下
~~~
<bean id="loginFilter" class="com.zrhis.system.security.DefaultUsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"></property>
<property name="authenticationSuccessHandler">
<bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/index.jsp"></property>
</bean>
</property>
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login.jsp"></property>
</bean>
</property>
</bean>
~~~
最后在http中加入custom-filter配置,將這個filter放在SpringSecurity的FORM_LOGIN_FILTER之前
~~~
<custom-filter ref="loginFilter" before="FORM_LOGIN_FILTER"/>
~~~
最后一種是直接替換掉SpringSecurity的UsernamePasswordAuthenticationFilter,這種比較復雜,但是更為合理,也是我現在正在用的。
如果用這種方法那么http 中的auto-config就必須去掉,而form-login配置也必須去掉,因為這個不需要了,里面的屬性都需要我們自行注入。
首先需要創建一個EntryPoint
~~~
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login.jsp" />
</bean>
~~~
然后在http中配置下
~~~
<sec:http access-decision-manager-ref="accessDecisionManager"
entry-point-ref="authenticationEntryPoint">
~~~
然后我們來寫CaptchaAuthenticationFilter,同樣需要繼承自UsernamePasswordAuthenticationFilter
~~~
public class CaptchaAuthenticationFilter extends UsernamePasswordAuthenticationFilter{
public static final String SPRING_SECURITY_FORM_CAPTCHA_KEY = "j_captcha";
public static final String SESSION_GENERATED_CAPTCHA_KEY = Constant.SESSION_GENERATED_CAPTCHA_KEY;
private String captchaParameter = SPRING_SECURITY_FORM_CAPTCHA_KEY;
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
String genCode = this.obtainGeneratedCaptcha(request);
String inputCode = this.obtainCaptcha(request);
if(genCode == null)
throw new CaptchaException(this.messages.getMessage("LoginAuthentication.captchaInvalid"));
if(!genCode.equalsIgnoreCase(inputCode)){
throw new CaptchaException(this.messages.getMessage("LoginAuthentication.captchaNotEquals"));
}
return super.attemptAuthentication(request, response);
}
protected String obtainCaptcha(HttpServletRequest request){
return request.getParameter(this.captchaParameter);
}
protected String obtainGeneratedCaptcha (HttpServletRequest request){
return (String)request.getSession().getAttribute(SESSION_GENERATED_CAPTCHA_KEY);
}
}
~~~
在配置文件中配置CaptchaAuthenticationFilter
~~~
<bean id="captchaAuthenticaionFilter" class="com.zrhis.system.security.CaptchaAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
<property name="filterProcessesUrl" value="/login.do" />
</bean>
<bean id="authenticationSuccessHandler" class="com.zrhis.system.security.SimpleLoginSuccessHandler">
<property name="defaultTargetUrl" value="/WEB-INF/app.jsp"></property>
<property name="forwardToDestination" value="true"></property>
</bean>
<bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login.jsp" />
</bean>
~~~
從配置文件中就可以看出來authenticationManager、authenticationFailureHandler、authenticationSuccessHandler、filterProcessesUrl等都需要我們自行注入了。
filterProcessesUrl定義的是登錄驗證的地址,默認的是j_spring_security_check這里我們改成login.do
authenticationSuccessHandler中的defaultTargetUrl定義的是登錄成功后跳轉到的頁面
authenticationFailureHandler中的defaultTargetUrl定義的是登錄失敗后跳轉到的頁面
我們的首頁app.jsp在/WEB-INF下所以需要使用服務器跳轉,所以需要將forwardToDestination設為true,因為客戶端跳轉是不能直接訪問WEB-INF下的內容的。
最后在http中將FORM_LOGIN_FILTER替換掉,最終http中完整的配置就變成了下面的內容
~~~
<sec:http access-decision-manager-ref="accessDecisionManager"
entry-point-ref="authenticationEntryPoint">
<sec:access-denied-handler ref="accessDeniedHandler"/>
<sec:session-management invalid-session-url="/login.jsp" />
<sec:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/>
<sec:custom-filter ref="captchaAuthenticaionFilter" position="FORM_LOGIN_FILTER"/>
</sec:http>
~~~
custom-filter中before是在這個filter之前,after是之后,position是替換。
這樣就可以實現對驗證碼的驗證了,效果如下

- 前言
- (大綱)----學習過程分享
- (1)----SpringSecurity3.2環境搭建
- (2)----SpringSecurity簡單測試
- (3)---- 自定義登錄頁面
- (4)---- 數據庫表結構的創建
- (5)---- 國際化配置及UserCache
- (6)---- 使用數據庫管理用戶及權限
- (7)---- 解決UsernameNotFoundException無法被捕獲的問題
- (8)---- 自定義決策管理器及修改權限前綴
- (9)---- 自定義AccessDeniedHandler
- (10)---- 自定義登錄成功后的處理程序及修改默認驗證地址
- (11)---- 使用數據庫來管理資源
- (12)---- 使用數據庫來管理方法
- (13)---- 驗證碼功能的實現
- (14)---- Logout和SessionManager