zoukankan      html  css  js  c++  java
  • 使用JCaptcha生成验证码

    在项目里用JCaptcha添加了验证码. 中间调试费了很多时间, 这里直接把步骤和结果的源代码贴出来吧.

    首先要到JCaptcha的官网去下载jar包, 目前使用 jcaptcha-1.0-all.jar 这个就够了, 如果你的lib中没有 commons-collections-3.2.1.jar 的话, 需要去 Apache Collections 网站下一个, 因为生成时使用的fasthashmap依赖于这个jar.

    JCaptcha 官网上 java doc已经已经更新至2.0alpha版, 但是发布的jar还是1.0, 所以java doc中提到的一些engine在jar中是没有的, 一些deprecated的类在1.0中依然需要使用.

    JCaptcha 官网上提供了一个最简单的5分钟速成样例, 直接使用DefaultManageableImageCaptchaService构建验证图.

    因为默认的验证图很难辨认, 所以还是需要自己定制一下, 以适应自己项目的需求.

    首先是扩展出自己的ImageCaptchaEngine, 命名为 CaptchaImageEngine.java . 这里借鉴了几个网络上前辈提供的例子, 做了一些修改

    public class CaptchaImageEngine extends ListImageCaptchaEngine
    {
        public static final Integer WORD_MIN_LENGTH = new Integer(4);
        public static final Integer WORD_MAX_LENGTH = new Integer(4);
    
        public static final Integer IMAGE_WIDTH = new Integer(160);
        public static final Integer IMAGE_HEIGHT = new Integer(50);
    
        public static final Integer FONT_MIN_SIZE = new Integer(30);
        public static final Integer FONT_MAX_SIZE = new Integer(35);
    
        protected void buildInitialFactories()
        {
            WordGenerator wordGenerator = (new RandomWordGenerator("23456789ABCDEFGHJKMNPQRSTUVWXY"));
    
            BackgroundGenerator backgroundGenerator = new UniColorBackgroundGenerator(IMAGE_WIDTH, IMAGE_HEIGHT);
    
            Font[] fontsList = new Font[]{Font.decode("Arial"), Font.decode("Georgia"), Font.decode("Verdana"), Font.decode("Courier New")};
            FontGenerator fontGenerator = new RandomFontGenerator(FONT_MIN_SIZE, FONT_MAX_SIZE, fontsList);
    
            RandomRangeColorGenerator cgen = new RandomRangeColorGenerator(
                    new int[] { 0, 128 },
                    new int[] { 0, 128 },
                    new int[] { 0, 196 }
                );
    
            TextDecorator[] textdecorators = new TextDecorator[]{new BaffleTextDecorator(new Integer(1), Color.WHITE)};
    
            TextPaster textPaster = new DecoratedRandomTextPaster(
                    WORD_MIN_LENGTH,
                    WORD_MAX_LENGTH,
                    cgen,
                    textdecorators
                );
    
            WaterFilter water = new WaterFilter();
            water.setAmplitude(5d);//振幅
            water.setAntialias(true);//锯齿或平滑
            water.setPhase(30d);//相位
            water.setWavelength(60d);
    
            WordToImage wordToImage = new DeformedComposedWordToImage(
                    fontGenerator,
                    backgroundGenerator,
                    textPaster,
                    new ImageDeformationByFilters(new ImageFilter[]{}),
                    new ImageDeformationByFilters(new ImageFilter[]{}),
                    new ImageDeformationByFilters(new ImageFilter[]{water})
                );
    
            addFactory(new GimpyFactory(wordGenerator, wordToImage));
        }
    }

    然后是提供生成验证图的静态方法的 CaptchaService.java . 这里就可以使用刚才建的ImageEngine来绘制验证图了

    public class CaptchaService
    {
        private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService(
                new FastHashMapCaptchaStore(),
                new CaptchaImageEngine(),
                180, 100000, 75000
            );
    
        private CaptchaService(){}
    
        public static BufferedImage getImageChallenge(String sid, Locale locale)
        {
            return instance.getImageChallengeForID(sid, locale);
        }
    
        public static BufferedImage getImageChallenge(String sid)
        {
            return instance.getImageChallengeForID(sid);
        }
    
        public static boolean validate(String sid, String input)
        {
            return instance.validateResponseForID(sid, input);
        }
    }

    这样, 在action中就可以直接调用了, 调用的方法分为两部分, 一部分是生成图片

    public String doGenerate()
        {
            try
            {
                // 获取session中的token用于生成验证图片,
                String token = getSession().getSession_token();
    
                // 生成验证图片
                BufferedImage challenge = CaptchaService.getImageChallenge(token);
    
                // 压缩为JPEG格式
                ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
                JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
                jpegEncoder.encode(challenge);
    
                // 置入action result的输出数据中
                this.put_streambytes("image/jpeg", jpegOutputStream.toByteArray());
            }
            catch (IllegalArgumentException e)
            {
                this.put_streambytes("image/jpeg", new byte[]{});
                logger.info("IllegalArgumentException");
                logger.debug("Exception Details", e);
            }
            catch (Exception e)
            {
                this.put_streambytes("image/jpeg", new byte[]{});
                logger.info("UnknownException");
                logger.debug("Exception Details", e);
            }
    
            return SUCCESS;
        }

    然后, 用于处理action result的方法, 会使用 ServletOutputStream 输出图片

    public class StreamProcessor {
    
        private static Logger logger = Logger.getLogger(RawProcessor.class);
    
        public static void process(HttpServletResponse res, String type, Object streamBytes)
        {
            try
            {
                res.setHeader("Cache-Control", "no-store");
                res.setHeader("Pragma", "no-cache");
                res.setDateHeader("Expires", 0);
                res.setContentType(type);
                ServletOutputStream responseOutputStream = res.getOutputStream();
                responseOutputStream.write((byte[])streamBytes);
                responseOutputStream.flush();
                responseOutputStream.close();
            }
            catch (Exception e)
            {
                logger.info("Unknown Exception");
                logger.debug("Exception details:", e);
            }
        }
    }

    另一方面, 需要在页面上添加对图片的引用, 因为需要制造点击刷新的效果, 使用javascript来生成html引用代码.
    前端的HTML是 (

     

    其中使用到的回调函数是

    function captcha_image(element_id, src) 
    {
        var joiner = '&';
        if (src.indexOf('?')== -1) joiner = '?';
        $("#"+element_id).html(' ');
    }

    后端响应这段js的action, 其作用, 是返回一段js代码, 让浏览器端去调用captcha_image()这个方法来生成引用图片的HTML代码

    public String doJsInclude()
        {
            DefaultRequestBean bean = new DefaultRequestBean();
            String elementId = bean.get("element");
            String output = "captcha_image(\""+elementId+"\",\""+baseLink("captcha_image")+"\");";
            this.put_raw_string(output);
            return SUCCESS;
        }

    在用户提交后, 用于验证用户提交的验证码内容的方法片段:

                String token = getSession().getSession_token();
                if (!CaptchaService.validate(token, this.captcha_input.toUpperCase()))
                {
                    flag = false;
                    this.put_error_msg("captcha_input", langRes.get("login_success"));
                }
                return flag;


  • 相关阅读:
    Oracle 推出 ODAC for Entity Framework 和 LINQ to Entities Beta版
    Entity Framework Feature CTP 5系列文章
    MonoDroid相关资源
    MSDN杂志上的Windows Phone相关文章
    微软学Android Market推出 Web Windows Phone Marketplace
    使用 Visual Studio Agent 2010 进行负载压力测试的安装指南
    MonoMac 1.0正式发布
    Shawn Wildermuth的《Architecting WP7 》系列文章
    使用.NET Mobile API即51Degrees.mobi检测UserAgent
    MongoDB 客户端 MongoVue
  • 原文地址:https://www.cnblogs.com/milton/p/4215076.html
Copyright © 2011-2022 走看看