- 驗證碼采用一個博客上的驗證碼 點擊跳轉
- 采用action的形式獲取驗證碼,并把驗證碼存入到shiro管理的session中
public void getGifCode(HttpServletResponse response,HttpServletRequest request){
try {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/gif");
/**
* gif格式動畫驗證碼
* 寬,高,位數。
*/
Captcha captcha = new GifCaptcha(146,42,4);
//輸出
ServletOutputStream out = response.getOutputStream();
captcha.out(out);
out.flush();
//存入Shiro會話session
System.out.println( captcha.text().toLowerCase());
TokenManager.setVal2Session(VerifyCodeUtils.V_CODE, captcha.text().toLowerCase());
} catch (Exception e) {
LoggerUtils.fmtError(getClass(),e, "獲取驗證碼異常:%s",e.getMessage());
}
}
- 驗證碼驗證的 Shiro 過濾器
public class JCaptchaValidateFilter extends AccessControlFilter{
/**
* 是否開啟驗證碼驗證 默認true
*/
private boolean jcaptchaEbabled = true;
/**
* 前臺提交的驗證碼參數名
*/
private String jcaptchaParam = "jcaptchaCode";
/**
* 驗證失敗后存儲到的屬性名
*/
private String failureKeyAttribute = "shiroLoginFailure";
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object o) throws Exception {
//1、設置驗證碼是否開啟屬性,頁面可以根據該屬性來決定是否顯示驗證碼
request.setAttribute("jcaptchaEbabled", jcaptchaEbabled);
HttpServletRequest httpRequest = WebUtils.toHttp(request);
//2、判斷驗證碼是否禁用 或不是表單提交(允許訪問)
if (jcaptchaEbabled == false || !"post".equalsIgnoreCase(httpRequest.getMethod())) {
return true;
}
//表單提交,校驗驗證碼的正確性
String storedCode = getSubject(request, response).getSession().getAttribute(Constatns.VERIFYCODE).toString();
String currentCode = httpRequest.getParameter(jcaptchaParam);
return StringUtils.equalsIgnoreCase(storedCode, currentCode);
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse servletResponse) throws Exception {
//如果驗證碼失敗了,存儲失敗 key 屬性
request.setAttribute(failureKeyAttribute, "jCaptcha.error");
return true;
}
public String getFailureKeyAttribute() {
return failureKeyAttribute;
}
public void setFailureKeyAttribute(String failureKeyAttribute) {
this.failureKeyAttribute = failureKeyAttribute;
}
public String getJcaptchaParam() {
return jcaptchaParam;
}
public void setJcaptchaParam(String jcaptchaParam) {
this.jcaptchaParam = jcaptchaParam;
}
public boolean isJcaptchaEbabled() {
return jcaptchaEbabled;
}
public void setJcaptchaEbabled(boolean jcaptchaEbabled) {
this.jcaptchaEbabled = jcaptchaEbabled;
}
}
- MyFormAuthenticationFilter ,表單提交時,先驗證驗證碼,如果驗證成功再走登錄流程
用于驗證碼驗證的 Shiro 攔截器在用于身份認證的攔截器之前運行;但是如果驗證碼驗證攔截器失敗了,就不需要進行身份認證攔截器流程了;所以需要修改下如FormAuthenticationFilter 身份認證攔截器,當驗證碼驗證失敗時不再走身份認證攔截器。
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if(request.getAttribute(getFailureKeyAttribute()) != null) {
return true;
}
return super.onAccessDenied(request, response);
}
}
- 配置文件的配置
<!-- 基于form表單的身份驗證過濾器 帶有驗證碼的過濾-->
<bean id="myformAuthenticationFilter" class="com.nanc.core.shiro.filter.MyFormAuthenticationFilter">
<property name="usernameParam" value="username"/>
<property name="passwordParam" value="password"/>
<property name="rememberMeParam" value="rememberMe"/>
<property name="loginUrl" value="/login"/>
<property name="failureKeyAttribute" value="shiroLoginFailure"/>
</bean>
<!-- 驗證碼的過濾器 -->
<bean id="jCaptchaFilter" class="com.nanc.core.shiro.filter.JCaptchaValidateFilter">
<property name="failureKeyAttribute" value="shiroLoginFailure"/>
<property name="jcaptchaParam" value="jcaptchaCode"/><!-- 頁面的參數名-->
<property name="jcaptchaEbabled" value="true"/>
</bean>
<!-- Shiro的Web過濾器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login"/>
<property name="filters">
<map>
<!--<entry key="authc" value-ref="formAuthenticationFilter"/>-->
<entry key="authc" value-ref="myformAuthenticationFilter"/>
<entry key="jcaptcha" value-ref="jCaptchaFilter"/>
<entry key="sysUser" value-ref="sysUserFilter"/>
<entry key="kickout" value-ref="kickoutFilter"/>
<!--添加ssl支持-->
<!--<entry key="ssl" value-ref="sslFilter"/>-->
<!-- 結束ssl支持-->
</map>
</property>
<property name="filterChainDefinitions">
<value>
/login=jcaptcha,authc
/loginDialog=authc
/logout=logout
/authenticated=authc
/dwz_jui/**=anon
/common/**=anon
/**=kickout,user,sysUser
</value>
</property>
</bean>