日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

第二十二章 集成驗(yàn)證碼——《跟我學(xué)Shiro》

系統(tǒng) 1711 0

?

目錄貼: ?跟我學(xué)Shiro目錄貼

?

在做用戶登錄功能時(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這種開源Java類庫(kù)生成驗(yàn)證碼圖片;JCaptcha提供了常見的如扭曲、加噪點(diǎn)等干擾支持。本章代碼基于《第十六章?綜合實(shí)例》。

?

一、添加 JCaptcha 依賴 ?

      <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)證碼存在。?

      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)證碼是否正確。??

      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ò)濾器。??

      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)行瀏覽器端緩存。?

?

      <!-- 驗(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ò)濾器。??

      public class JCaptchaValidateFilter extends AccessControlFilter {
    private boolean jcaptchaEbabled = true;//是否開啟驗(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)證碼是否開啟屬性,頁(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)證攔截器。?

      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 ? ? ???

      <!-- 基于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è)面

      <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è)面:?

第二十二章 集成驗(yàn)證碼——《跟我學(xué)Shiro》
??

?

?

示例源代碼: https://github.com/zhangkaitao/shiro-example ;可加群 231889722?探討Spring/Shiro技術(shù)。

? ? ? ??

??

第二十二章 集成驗(yàn)證碼——《跟我學(xué)Shiro》


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 普格县| 舞阳县| 亳州市| 尼木县| 济宁市| 尼勒克县| 怀宁县| 尤溪县| 修水县| 仪征市| 杨浦区| 孟连| 贵德县| 兴业县| 南康市| 射洪县| 济源市| 安新县| 丰都县| 砀山县| 彰化县| 定安县| 高邮市| 南城县| 页游| 罗源县| 梁河县| 涞水县| 治县。| 温州市| 牡丹江市| 淅川县| 舒城县| 马边| 抚顺市| 三河市| 山阴县| 博罗县| 庆云县| 盐城市| 顺平县|