在做用户登录功能时,非常多时候都须要验证码支持,验证码的目的是为了防止机器人模拟真有用户登录而恶意訪问,如暴力破解用户password/恶意评论等。

眼下也有一些验证码比較简单,通过一些OCR工具就能够解析出来。另外另一些验证码比較复杂(一般通过如扭曲、加线条/噪点等干扰)防止OCR工具识别。可是在中国就是人多。机器干不了的能够交给人来完毕,所以在中国就有非常多打码平台。人工识别验证码;因此即使比較复杂的如填字、算数等类型的验证码还是能识别的。所以验证码也不是绝对可靠的,眼下比較可靠还是手机验证码,可是对于用户来说相对于验证码还是比較麻烦的。

对于验证码图片的生成。能够自己通过如Java提供的图像API自己去生成,也能够借助如JCaptcha这样的开源Java类库生成验证码图片;JCaptcha提供了常见的如扭曲、加噪点等干扰支持。本章代码基于《第十六章 综合实例》。

一、加入JCaptcha依赖

Java代码  
  1. </version>
  2. </version>
  3. <exclusions>
  4. <exclusion>
  5. <artifactId>servlet-api</artifactId>
  6. <groupId>javax.servlet</groupId>
  7. </exclusion>
  8. </exclusions>
  9. </dependency>

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

二、GMailEngine

来自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(眼下无法訪问了),仿照JCaptcha2.0编写类似GMail验证码的样式;详细请參考com.github.zhangkaitao.shiro.chapter22.jcaptcha.GMailEngine。

三、MyManageableImageCaptchaService

提供了推断仓库中是否有对应的验证码存在。

Java代码  
  1. public class MyManageableImageCaptchaService extends
  2. DefaultManageableImageCaptchaService {
  3. public MyManageableImageCaptchaService(
  4. com.octo.captcha.service.captchastore.CaptchaStore captchaStore,
  5. com.octo.captcha.engine.CaptchaEngine captchaEngine,
  6. int minGuarantedStorageDelayInSeconds,
  7. int maxCaptchaStoreSize,
  8. int captchaStoreLoadBeforeGarbageCollection) {
  9. super(captchaStore, captchaEngine, minGuarantedStorageDelayInSeconds,
  10. maxCaptchaStoreSize, captchaStoreLoadBeforeGarbageCollection);
  11. }
  12. public boolean hasCapcha(String id, String userCaptchaResponse) {
  13. return store.getCaptcha(id).validateResponse(userCaptchaResponse);
  14. }
  15. }

四、JCaptcha工具类

提供对应的API来验证当前请求输入的验证码是否正确。

Java代码  
  1. , , );
  2. public static boolean validateResponse(
  3. HttpServletRequest request, String userCaptchaResponse) {
  4. if (request.getSession(false) == null) return false;
  5. boolean validated = false;
  6. try {
  7. String id = request.getSession().getId();
  8. validated =
  9. captchaService.validateResponseForID(id, userCaptchaResponse)
  10. .booleanValue();
  11. } catch (CaptchaServiceException e) {
  12. e.printStackTrace();
  13. }
  14. return validated;
  15. }
  16. public static boolean hasCaptcha(
  17. HttpServletRequest request, String userCaptchaResponse) {
  18. if (request.getSession(false) == null) return false;
  19. boolean validated = false;
  20. try {
  21. String id = request.getSession().getId();
  22. validated = captchaService.hasCapcha(id, userCaptchaResponse);
  23. } catch (CaptchaServiceException e) {
  24. e.printStackTrace();
  25. }
  26. return validated;
  27. }
  28. }

validateResponse():验证当前请求输入的验证码否正确;并从CaptchaService中删除已经生成的验证码;

hasCaptcha():验证当前请求输入的验证码是否正确;但不从CaptchaService中删除已经生成的验证码(比方Ajax验证时能够使用。防止多次生成验证码);

五、JCaptchaFilter

用于生成验证码图片的过滤器。

Java代码  
  1. public class JCaptchaFilter extends OncePerRequestFilter {
  2. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
  3. response.setDateHeader("Expires", 0L);
  4. response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
  5. response.addHeader("Cache-Control", "post-check=0, pre-check=0");
  6. response.setHeader("Pragma", "no-cache");
  7. response.setContentType("image/jpeg");
  8. String id = request.getRequestedSessionId();
  9. BufferedImage bi = JCaptcha.captchaService.getImageChallengeForID(id);
  10. ServletOutputStream out = response.getOutputStream();
  11. ImageIO.write(bi, "jpg", out);
  12. try {
  13. out.flush();
  14. } finally {
  15. out.close();
  16. }
  17. }
  18. }

CaptchaService使用当前会话ID当作key获取对应的验证码图片;另外须要设置响应内容不进行浏览器端缓存。

Java代码  
  1. <!-- 验证码过滤器须要放到Shiro之后 由于Shiro将包装HttpSession 假设不。可能造成两次的sesison id 不一样 -->
  2. <filter>
  3. <filter-name>JCaptchaFilter</filter-name>
  4. <filter-class>
  5. com.github.zhangkaitao.shiro.chapter22.jcaptcha.JCaptchaFilter
  6. </filter-class>
  7. </filter>
  8. <filter-mapping>
  9. <filter-name>JCaptchaFilter</filter-name>
  10. <url-pattern>/jcaptcha.jpg</url-pattern>
  11. </filter-mapping>

这样就能够在页面使用/jcaptcha.jpg地址显示验证码图片。

六、JCaptchaValidateFilter

用于验证码验证的Shiro过滤器。

Java代码  
  1. public class JCaptchaValidateFilter extends AccessControlFilter {
  2. private boolean jcaptchaEbabled = true;//是否开启验证码支持
  3. private String jcaptchaParam = "jcaptchaCode";//前台提交的验证码參数名
  4. private String failureKeyAttribute = "shiroLoginFailure"; //验证失败后存储到的属性名
  5. public void setJcaptchaEbabled(boolean jcaptchaEbabled) {
  6. this.jcaptchaEbabled = jcaptchaEbabled;
  7. }
  8. public void setJcaptchaParam(String jcaptchaParam) {
  9. this.jcaptchaParam = jcaptchaParam;
  10. }
  11. public void setFailureKeyAttribute(String failureKeyAttribute) {
  12. this.failureKeyAttribute = failureKeyAttribute;
  13. }
  14. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
  15. //1、设置验证码是否开启属性,页面能够依据该属性来决定是否显示验证码
  16. request.setAttribute("jcaptchaEbabled", jcaptchaEbabled);
  17. HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
  18. //2、推断验证码是否禁用 或不是表单提交(同意訪问)
  19. if (jcaptchaEbabled == false || !"post".equalsIgnoreCase(httpServletRequest.getMethod())) {
  20. return true;
  21. }
  22. //3、此时是表单提交。验证验证码是否正确
  23. return JCaptcha.validateResponse(httpServletRequest, httpServletRequest.getParameter(jcaptchaParam));
  24. }
  25. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
  26. //假设验证码失败了。存储失败key属性
  27. request.setAttribute(failureKeyAttribute, "jCaptcha.error");
  28. return true;
  29. }
  30. }

七、MyFormAuthenticationFilter

用于验证码验证的Shiro拦截器在用于身份认证的拦截器之前执行;可是假设验证码验证拦截器失败了。就不须要进行身份认证拦截器流程了;所以须要改动下如FormAuthenticationFilter身份认证拦截器,当验证码验证失败时不再走身份认证拦截器。

Java代码  
  1. public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
  2. protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
  3. if(request.getAttribute(getFailureKeyAttribute()) != null) {
  4. return true;
  5. }
  6. return super.onAccessDenied(request, response, mappedValue);
  7. }
  8. }

即假设之前已经错了,那直接跳过就可以。

八、spring-config-shiro.xml

Java代码  
  1. <!-- 基于Form表单的身份验证过滤器 -->
  2. <bean id="authcFilter"
  3. class="com.github.zhangkaitao.shiro.chapter22.jcaptcha.MyFormAuthenticationFilter">
  4. <property name="usernameParam" value="username"/>
  5. <property name="passwordParam" value="password"/>
  6. <property name="rememberMeParam" value="rememberMe"/>
  7. <property name="failureKeyAttribute" value="shiroLoginFailure"/>
  8. </bean>
  9. <bean id="jCaptchaValidateFilter"
  10. class="com.github.zhangkaitao.shiro.chapter22.jcaptcha.JCaptchaValidateFilter">
  11. <property name="jcaptchaEbabled" value="true"/>
  12. <property name="jcaptchaParam" value="jcaptchaCode"/>
  13. <property name="failureKeyAttribute" value="shiroLoginFailure"/>
  14. </bean>
  15. <!-- Shiro的Web过滤器 -->
  16. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
  17. <property name="securityManager" ref="securityManager"/>
  18. <property name="loginUrl" value="/login"/>
  19. <property name="filters">
  20. <util:map>
  21. <entry key="authc" value-ref="authcFilter"/>
  22. <entry key="sysUser" value-ref="sysUserFilter"/>
  23. <entry key="jCaptchaValidate" value-ref="jCaptchaValidateFilter"/>
  24. </util:map>
  25. </property>
  26. <property name="filterChainDefinitions">
  27. <value>
  28. /static/** = anon
  29. /jcaptcha* = anon
  30. /login = jCaptchaValidate,authc
  31. /logout = logout
  32. /authenticated = authc
  33. /** = user,sysUser
  34. </value>
  35. </property>
  36. </bean>

九、login.jsp登录页面

Java代码  
  1. <c:if test="${jcaptchaEbabled}">
  2. 验证码:
  3. <input type="text" name="jcaptchaCode">
  4. <img class="jcaptcha-btn jcaptcha-img"
  5. src="${pageContext.request.contextPath}/jcaptcha.jpg" title="点击更换验证码">
  6. <a class="jcaptcha-btn" href="javascript:;">换一张</a>
  7. <br/>
  8. </c:if>

依据jcaptchaEbabled来显示验证码图片。

十、測试

输入http://localhost:8080/chapter22将重定向到登录页面。输入正确的username/password/验证码就可以成功登录,假设输入错误的验证码,将显示验证码错误页面:

演示样例源码:https://github.com/zhangkaitao/shiro-example

本文借鉴于:http://jinnianshilongnian.iteye.com/blog/2046041

Shiro学习(22)集成验证码的更多相关文章

  1. Shiro学习笔记(5)——web集成

    Web集成 shiro配置文件shiroini 界面 webxml最关键 Servlet 測试 基于 Basic 的拦截器身份验证 Web集成 大多数情况.web项目都会集成spring.shiro在 ...

  2. Shiro学习(总结)

    声明:本文原文地址:http://www.iteye.com/blogs/subjects/shiro 感谢开涛提供的博文,让我学到了非常多.在这里由衷的感谢你,同一时候我强烈的推荐开涛的博文.他的博 ...

  3. Apache shiro学习总结

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  4. Shiro学习

    Shiro学习资源 Shiro官网,http://shiro.apache.org/index.html 学习网站链接,http://blog.java1234.com/blog/articles/4 ...

  5. Shiro 学习

    <转载于 凯涛 博客> Shiro目录 第一章  Shiro简介 第二章  身份验证 第三章  授权 第四章  INI配置 第五章  编码/加密 第六章  Realm及相关对象 第七章  ...

  6. SpringBoot中Shiro使用Pac4j集成CAS认证

    SpringBoot中Shiro使用Pac4j集成CAS认证 Pac4j 简介 Pac4j与Shiro,Spring Security一样都是权限框架,并且提供了OAuth - SAML - CAS ...

  7. SpringMVC+Apache Shiro+JPA(hibernate)案例教学(三)给Shiro登录验证加上验证码

    序: 给Shiro加入验证码,有多种方式,当然你也可以通过继承修改FormAuthenticationFilter类,通过Shiro去验证验证码.具体实现请百度: 应用Shiro到Web Applic ...

  8. 深度学习的集成方法——Ensemble Methods for Deep Learning Neural Networks

    本文主要参考Ensemble Methods for Deep Learning Neural Networks一文. 1. 前言 神经网络具有很高的方差,不易复现出结果,而且模型的结果对初始化参数异 ...

  9. Apache Shiro学习-2-Apache Shiro Web Support

     Apache Shiro Web Support  1. 配置 将 Shiro 整合到 Web 应用中的最简单方式是在 web.xml 的 Servlet ContextListener 和 Fil ...

  10. shiro学习笔记_0600_自定义realm实现授权

    博客shiro学习笔记_0400_自定义Realm实现身份认证 介绍了认证,这里介绍授权. 1,仅仅通过配置文件来指定权限不够灵活且不方便.在实际的应用中大多数情况下都是将用户信息,角色信息,权限信息 ...

随机推荐

  1. Pro ASP.NET Core MVC 第6版翻译 目录页

    Pro ASP.NET Core MVC 第6版 目录 第一部分 第一章 ASP.NET Core MVC 的前世今生 第二章 第一个MVC应用程序(上) 第二章 第一个MVC应用程序(下) 第三章 ...

  2. mongo 3.4分片集群系列之六:详解配置数据库

    这个系列大致想跟大家分享以下篇章: 1.mongo 3.4分片集群系列之一:浅谈分片集群 2.mongo 3.4分片集群系列之二:搭建分片集群--哈希分片 3.mongo 3.4分片集群系列之三:搭建 ...

  3. JS高级——Blob处理二进制文件

    https://www.cnblogs.com/hhhyaaon/p/5928152.html

  4. 常用css属性总结

    边框修饰:border------>top,bottom,left,right上下左右边框 分为:color,类型style{ groove,dashed,ridge,solid}一个值---- ...

  5. BZOJ 3884: 上帝与集合的正确用法 扩展欧拉定理 + 快速幂

    Code: #include<bits/stdc++.h> #define maxn 10000004 #define ll long long using namespace std; ...

  6. Redis系列(八)--缓存穿透、雪崩、更新策略

    1.缓存更新策略 1.LRU/LFU/FIFO算法剔除:例如maxmemory-policy 2.超时剔除,过期时间expire,对于一些用户可以容忍延时更新的数据,例如文章简介内容改了几个字 3.主 ...

  7. input password密码验证跳转页面

    代码如下: 查询密码 <input type="password" id="pwd" /> 页面如下: 密码校验成功后跳转页面: window.lo ...

  8. 06C语言运算符

    C语言运算符 算术运算符 运算符 描述 + 把两个操作数相加 - 从第一个操作数中减去第二个操作数 * 把两个操作数相乘 / 分子除以分母 % 取模运算符,整除后的余数 ++ 自增运算符,整数值增加 ...

  9. TWaver动画之雷达扫描效果

    UI和功能是好的产品的两个重要因素,很多产品往往只注重功能上的设计,而忽略了UI.在这个“看脸”的时代,就算产品的功能很强大,如果UI跟不上步伐,你的产品都会在客户心中大打折扣.做安全和监控的项目中经 ...

  10. 洛谷——P2827 蚯蚓

    P2827 蚯蚓 题目描述 本题中,我们将用符号 \lfloor c \rfloor⌊c⌋ 表示对 cc 向下取整,例如:\lfloor 3.0 \rfloor = \lfloor 3.1 \rflo ...