日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Shiro学习(22)集成验证码

發(fā)布時(shí)間:2024/1/8 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Shiro学习(22)集成验证码 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在做用戶登錄功能時(shí),很多時(shí)候都需要驗(yàn)證碼支持,驗(yàn)證碼的目的是為了防止機(jī)器人模擬真實(shí)用戶登錄而惡意訪問(wèn),如暴力破解用戶密碼/惡意評(píng)論等。目前也有一些驗(yàn)證碼比較簡(jiǎn)單,通過(guò)一些OCR工具就可以解析出來(lái);另外還有一些驗(yàn)證碼比較復(fù)雜(一般通過(guò)如扭曲、加線條/噪點(diǎn)等干擾)防止OCR工具識(shí)別;但是在中國(guó)就是人多,機(jī)器干不了的可以交給人來(lái)完成,所以在中國(guó)就有很多打碼平臺(tái),人工識(shí)別驗(yàn)證碼;因此即使比較復(fù)雜的如填字、算數(shù)等類型的驗(yàn)證碼還是能識(shí)別的。所以驗(yàn)證碼也不是絕對(duì)可靠的,目前比較可靠還是手機(jī)驗(yàn)證碼,但是對(duì)于用戶來(lái)說(shuō)相對(duì)于驗(yàn)證碼還是比較麻煩的。

對(duì)于驗(yàn)證碼圖片的生成,可以自己通過(guò)如Java提供的圖像API自己去生成,也可以借助如JCaptcha這種開(kāi)源Java類庫(kù)生成驗(yàn)證碼圖片;JCaptcha提供了常見(jiàn)的如扭曲、加噪點(diǎn)等干擾支持。本章代碼基于《第十六章 綜合實(shí)例》。

一、添加JCaptcha依賴
Java代碼

<dependency> <groupId>com.octo.captcha</groupId> <artifactId>jcaptcha</artifactId> <version>2.0-alpha-1</version> </dependency> <dependency> <groupId>com.octo.captcha</groupId> <artifactId>jcaptcha-integration-simple-servlet</artifactId> <version>2.0-alpha-1</version> <exclusions> <exclusion> <artifactId>servlet-api</artifactId> <groupId>javax.servlet</groupId> </exclusion> </exclusions> </dependency>

com.octo.captcha . jcaptcha 提供了jcaptcha 核心;而jcaptcha-integration-simple-servlet提供了與Servlet集成。

二、GMailEngine
來(lái)自https://code.google.com/p/musicvalley/source/browse/trunk/musicvalley/doc/springSecurity/springSecurityIII/src/main/java/com/spring/security/jcaptcha/GMailEngine.java?spec=svn447&r=447(目前無(wú)法訪問(wèn)了),仿照J(rèn)Captcha2.0編寫類似GMail驗(yàn)證碼的樣式;具體請(qǐng)參考com.github.zhangkaitao.shiro.chapter22.jcaptcha.GMailEngine。

三、MyManageableImageCaptchaService
提供了判斷倉(cāng)庫(kù)中是否有相應(yīng)的驗(yàn)證碼存在。
Java代碼

public class MyManageableImageCaptchaService extends DefaultManageableImageCaptchaService { public MyManageableImageCaptchaService( com.octo.captcha.service.captchastore.CaptchaStore captchaStore, com.octo.captcha.engine.CaptchaEngine captchaEngine, int minGuarantedStorageDelayInSeconds, int maxCaptchaStoreSize, int captchaStoreLoadBeforeGarbageCollection) { super(captchaStore, captchaEngine, minGuarantedStorageDelayInSeconds, maxCaptchaStoreSize, captchaStoreLoadBeforeGarbageCollection); } public boolean hasCapcha(String id, String userCaptchaResponse) { return store.getCaptcha(id).validateResponse(userCaptchaResponse); } }

四、JCaptcha工具類
提供相應(yīng)的API來(lái)驗(yàn)證當(dāng)前請(qǐng)求輸入的驗(yàn)證碼是否正確。
Java代碼

public class JCaptcha { public static final MyManageableImageCaptchaService captchaService = new MyManageableImageCaptchaService(new FastHashMapCaptchaStore(), new GMailEngine(), 180, 100000, 75000); public static boolean validateResponse( HttpServletRequest request, String userCaptchaResponse) { if (request.getSession(false) == null) return false; boolean validated = false; try { String id = request.getSession().getId(); validated = captchaService.validateResponseForID(id, userCaptchaResponse) .booleanValue(); } catch (CaptchaServiceException e) { e.printStackTrace(); } return validated; } public static boolean hasCaptcha( HttpServletRequest request, String userCaptchaResponse) { if (request.getSession(false) == null) return false; boolean validated = false; try { String id = request.getSession().getId(); validated = captchaService.hasCapcha(id, userCaptchaResponse); } catch (CaptchaServiceException e) { e.printStackTrace(); } return validated; } }

validateResponse():驗(yàn)證當(dāng)前請(qǐng)求輸入的驗(yàn)證碼否正確;并從CaptchaService中刪除已經(jīng)生成的驗(yàn)證碼;
hasCaptcha():驗(yàn)證當(dāng)前請(qǐng)求輸入的驗(yàn)證碼是否正確;但不從CaptchaService中刪除已經(jīng)生成的驗(yàn)證碼(比如Ajax驗(yàn)證時(shí)可以使用,防止多次生成驗(yàn)證碼);

五、JCaptchaFilter
用于生成驗(yàn)證碼圖片的過(guò)濾器。
Java代碼

public class JCaptchaFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { response.setDateHeader("Expires", 0L); response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); response.addHeader("Cache-Control", "post-check=0, pre-check=0"); response.setHeader("Pragma", "no-cache"); response.setContentType("image/jpeg"); String id = request.getRequestedSessionId(); BufferedImage bi = JCaptcha.captchaService.getImageChallengeForID(id); ServletOutputStream out = response.getOutputStream(); ImageIO.write(bi, "jpg", out); try { out.flush(); } finally { out.close(); } } }

CaptchaService使用當(dāng)前會(huì)話ID當(dāng)作key獲取相應(yīng)的驗(yàn)證碼圖片;另外需要設(shè)置響應(yīng)內(nèi)容不進(jìn)行瀏覽器端緩存。

Java代碼

<!-- 驗(yàn)證碼過(guò)濾器需要放到Shiro之后 因?yàn)镾hiro將包裝HttpSession 如果不,可能造成兩次的sesison id 不一樣 --> <filter> <filter-name>JCaptchaFilter</filter-name> <filter-class> com.github.zhangkaitao.shiro.chapter22.jcaptcha.JCaptchaFilter </filter-class> </filter> <filter-mapping> <filter-name>JCaptchaFilter</filter-name> <url-pattern>/jcaptcha.jpg</url-pattern> </filter-mapping>

這樣就可以在頁(yè)面使用/jcaptcha.jpg地址顯示驗(yàn)證碼圖片。

六、JCaptchaValidateFilter
用于驗(yàn)證碼驗(yàn)證的Shiro過(guò)濾器。
Java代碼

public class JCaptchaValidateFilter extends AccessControlFilter { private boolean jcaptchaEbabled = true;//是否開(kāi)啟驗(yàn)證碼支持 private String jcaptchaParam = "jcaptchaCode";//前臺(tái)提交的驗(yàn)證碼參數(shù)名 private String failureKeyAttribute = "shiroLoginFailure"; //驗(yàn)證失敗后存儲(chǔ)到的屬性名 public void setJcaptchaEbabled(boolean jcaptchaEbabled) { this.jcaptchaEbabled = jcaptchaEbabled; } public void setJcaptchaParam(String jcaptchaParam) { this.jcaptchaParam = jcaptchaParam; } public void setFailureKeyAttribute(String failureKeyAttribute) { this.failureKeyAttribute = failureKeyAttribute; } protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { //1、設(shè)置驗(yàn)證碼是否開(kāi)啟屬性,頁(yè)面可以根據(jù)該屬性來(lái)決定是否顯示驗(yàn)證碼 request.setAttribute("jcaptchaEbabled", jcaptchaEbabled); HttpServletRequest httpServletRequest = WebUtils.toHttp(request); //2、判斷驗(yàn)證碼是否禁用 或不是表單提交(允許訪問(wèn)) if (jcaptchaEbabled == false || !"post".equalsIgnoreCase(httpServletRequest.getMethod())) { return true; } //3、此時(shí)是表單提交,驗(yàn)證驗(yàn)證碼是否正確 return JCaptcha.validateResponse(httpServletRequest, httpServletRequest.getParameter(jcaptchaParam)); } protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { //如果驗(yàn)證碼失敗了,存儲(chǔ)失敗key屬性 request.setAttribute(failureKeyAttribute, "jCaptcha.error"); return true; } }

七、MyFormAuthenticationFilter
用于驗(yàn)證碼驗(yàn)證的Shiro攔截器在用于身份認(rèn)證的攔截器之前運(yùn)行;但是如果驗(yàn)證碼驗(yàn)證攔截器失敗了,就不需要進(jìn)行身份認(rèn)證攔截器流程了;所以需要修改下如FormAuthenticationFilter身份認(rèn)證攔截器,當(dāng)驗(yàn)證碼驗(yàn)證失敗時(shí)不再走身份認(rèn)證攔截器。
Java代碼

public class MyFormAuthenticationFilter extends FormAuthenticationFilter { protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { if(request.getAttribute(getFailureKeyAttribute()) != null) { return true; } return super.onAccessDenied(request, response, mappedValue); } }

即如果之前已經(jīng)錯(cuò)了,那直接跳過(guò)即可。

八、spring-config-shiro.xml
Java代碼

<!-- 基于Form表單的身份驗(yàn)證過(guò)濾器 --> <bean id="authcFilter" class="com.github.zhangkaitao.shiro.chapter22.jcaptcha.MyFormAuthenticationFilter"> <property name="usernameParam" value="username"/> <property name="passwordParam" value="password"/> <property name="rememberMeParam" value="rememberMe"/> <property name="failureKeyAttribute" value="shiroLoginFailure"/> </bean> <bean id="jCaptchaValidateFilter" class="com.github.zhangkaitao.shiro.chapter22.jcaptcha.JCaptchaValidateFilter"> <property name="jcaptchaEbabled" value="true"/> <property name="jcaptchaParam" value="jcaptchaCode"/> <property name="failureKeyAttribute" value="shiroLoginFailure"/> </bean> <!-- Shiro的Web過(guò)濾器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/login"/> <property name="filters"> <util:map> <entry key="authc" value-ref="authcFilter"/> <entry key="sysUser" value-ref="sysUserFilter"/> <entry key="jCaptchaValidate" value-ref="jCaptchaValidateFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /static/** = anon /jcaptcha* = anon /login = jCaptchaValidate,authc /logout = logout /authenticated = authc /** = user,sysUser </value> </property> </bean>

九、login.jsp登錄頁(yè)面
Java代碼

<c:if test="${jcaptchaEbabled}"> 驗(yàn)證碼: <input type="text" name="jcaptchaCode"> <img class="jcaptcha-btn jcaptcha-img" src="${pageContext.request.contextPath}/jcaptcha.jpg" title="點(diǎn)擊更換驗(yàn)證碼"> <a class="jcaptcha-btn" href="javascript:;">換一張</a> <br/> </c:if>

根據(jù)jcaptchaEbabled來(lái)顯示驗(yàn)證碼圖片。

十、測(cè)試
輸入http://localhost:8080/chapter22將重定向到登錄頁(yè)面;輸入正確的用戶名/密碼/驗(yàn)證碼即可成功登錄,如果輸入錯(cuò)誤的驗(yàn)證碼,將顯示驗(yàn)證碼錯(cuò)誤頁(yè)面:

示例源代碼:https://github.com/zhangkaitao/shiro-example
本文借鑒于:http://jinnianshilongnian.iteye.com/blog/2046041

總結(jié)

以上是生活随笔為你收集整理的Shiro学习(22)集成验证码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。