您的位置:首页 > 其它

shiro安全框架扩展教程--验证码的安全(jcaptcha框架)

2014-11-02 20:08 597 查看
        我们看到很多网站上都有验证码的功能,因为他们需要防止机器人注册等等,导致数据膨胀,或者是暴力破解,但是验证码做的难以破解是比较困难的,因为现在机器识别

功能是灰常强大的;要做一个比较难以被机器识别的验证码应该要扭曲旋转,连体,多色彩,干扰线,不要说什么来个微积分什么的,那是给普通人用的玩意吗?我们要追求

大众化,所以还是按照传统的标准来搞

我们看到网上都流传很多验证码框架,例如jcaptcha,kcaptcha等等.下面我展示下如何使用jcaptcha实现一个自定义的验证码,首先用过jcaptcha的人都知道他的验证码内容

是不支持放到cookie里面,而是放到本地的mapstore的fastmap里面,所以很明显是不支持集群的,所以下面也看看我是如何扩展

先扩展一个验证码的样式类

package com.silvery.plugin.validcode.jcaptcha;

import java.awt.Font;
import java.awt.image.ImageFilter;

import com.jhlabs.image.WaterFilter;
import com.octo.captcha.component.image.backgroundgenerator.AbstractBackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator.FunkyBackgroundGenerator;
import com.octo.captcha.component.image.color.RandomRangeColorGenerator;
import com.octo.captcha.component.image.deformation.ImageDeformation;
import com.octo.captcha.component.image.deformation.ImageDeformationByFilters;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;
import com.octo.captcha.component.image.textpaster.DecoratedRandomTextPaster;
import com.octo.captcha.component.image.textpaster.TextPaster;
import com.octo.captcha.component.image.textpaster.textdecorator.LineTextDecorator;
import com.octo.captcha.component.image.textpaster.textdecorator.TextDecorator;
import com.octo.captcha.component.image.wordtoimage.DeformedComposedWordToImage;
import com.octo.captcha.component.image.wordtoimage.WordToImage;
import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator;
import com.octo.captcha.component.word.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import com.octo.captcha.image.gimpy.GimpyFactory;

/**
* 自定义验证码内容样式(通过源码改编)
*
* @author shadow
* @email 124010356@qq.com
* @create 2012.04.28
*/

public class SimpleCaptchaEngine extends ListImageCaptchaEngine {
/**
* this method should be implemented as folow :
* <ul>
* <li>First construct all the factories you want to initialize the gimpy
* with</li>
* <li>then call the this.addFactoriy method for each factory</li>
* </ul>
*/

protected void buildInitialFactories() {

// build filters 波浪实现类
WaterFilter water = new WaterFilter();

water.setAmplitude(3d);
water.setAntialias(true);
water.setPhase(30d);
water.setWavelength(80d);

ImageDeformation backDef = new ImageDeformationByFilters(new ImageFilter[] {});
ImageDeformation textDef = new ImageDeformationByFilters(new ImageFilter[] {});
ImageDeformation postDef = new ImageDeformationByFilters(new ImageFilter[] { water });

// word generator
WordGenerator dictionnaryWords = new RandomWordGenerator("abcdefhjkmnprstuvwxyz23456789");
// wordtoimage components

int[] R = new int[] { 0, 120 };
int[] G = new int[] { 0, 120 };
int[] B = new int[] { 0, 120 };

RandomRangeColorGenerator colors = new RandomRangeColorGenerator(R, G, B);

// Arial,Tahoma,Verdana,Helvetica,宋体,黑体,幼圆, 字体大小
Font[] fonts = new Font[] { new Font("Arial", 0, 10), new Font("Tahoma", 0, 10), new Font("Verdana", 0, 10),
new Font("Helvetica", 0, 10), new Font("宋体", 0, 10), new Font("黑体", 0, 10), new Font("幼圆", 0, 10) };

// 设置字符以及干扰线颜色
RandomRangeColorGenerator lineColors = new RandomRangeColorGenerator(R, G, B);

// 添加干扰线(可选取圆点干扰实现类BaffleTextDecorator LineTextDecorator)
TextPaster randomPaster = new DecoratedRandomTextPaster(4, 4, colors, true,
new TextDecorator[] { new LineTextDecorator(1, lineColors) });

RandomRangeColorGenerator backColorGenerator = new RandomRangeColorGenerator(new int[] { 75, 255 }, new int[] {
75, 255 }, new int[] { 75, 255 });

// 背景描绘
AbstractBackgroundGenerator back = new FunkyBackgroundGenerator(140, 50, backColorGenerator);

FontGenerator shearedFont = new RandomFontGenerator(35, 0, fonts);
// word2image 1
WordToImage word2image = new DeformedComposedWordToImage(shearedFont, back, randomPaster, backDef, textDef,
postDef);
// 输入图片
this.addFactory(new GimpyFactory(dictionnaryWords, word2image));

}

}

再写一个存放验证码类的实现类,简单的来说就是自己实现一个CaptchaStore接口的类,我们的验证码内容都是从这里读写

package com.silvery.plugin.validcode.jcaptcha;

import java.util.Collection;
import java.util.Locale;

import net.rubyeye.xmemcached.MemcachedClient;

import org.apache.commons.collections.CollectionUtils;

import com.octo.captcha.Captcha;
import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.captchastore.CaptchaAndLocale;
import com.octo.captcha.service.captchastore.CaptchaStore;
import com.silvery.core.spring.context.SpringHolder;

// Referenced classes of package com.octo.captcha.service.captchastore:
// CaptchaAndLocale, CaptchaStore

public class MemcacheCaptchaStore implements CaptchaStore {

private Object getCaptchaById(String id) {
try {
return getClient().get(id);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

private MemcachedClient getClient() {
Object obj = SpringHolder.getBean(MemcachedClient.class);
if (obj == null) {
throw new RuntimeException("Not found memcache instance");
}
return (MemcachedClient) obj;
}

public boolean hasCaptcha(String id) {
try {
if (getCaptchaById(id) != null) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

public void storeCaptcha(String id, Captcha captcha) throws CaptchaServiceException {
try {
getClient().set(id, 1800, new CaptchaAndLocale(captcha));
} catch (Exception e) {
e.printStackTrace();
}
}

public void storeCaptcha(String id, Captcha captcha, Locale locale) throws CaptchaServiceException {
try {
getClient().set(id, 1800, new CaptchaAndLocale(captcha, locale));
} catch (Exception e) {
throw new CaptchaServiceException(e);
}
}

public Captcha getCaptcha(String id) throws CaptchaServiceException {
try {
Object captchaAndLocale = getCaptchaById(id);
return captchaAndLocale == null ? null : ((CaptchaAndLocale) captchaAndLocale).getCaptcha();
} catch (Exception e) {
throw new CaptchaServiceException(e);
}
}

public Locale getLocale(String id) throws CaptchaServiceException {
try {
Object captchaAndLocale = getCaptchaById(id);
return captchaAndLocale == null ? null : ((CaptchaAndLocale) captchaAndLocale).getLocale();
} catch (Exception e) {
throw new CaptchaServiceException(e);
}
}

public boolean removeCaptcha(String id) {
try {
if (getCaptcha(id) != null) {
return getClient().delete(id);
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

public int getSize() {
return 0;
}

public Collection<?> getKeys() {
return CollectionUtils.EMPTY_COLLECTION;
}

public void empty() {

}

public void initAndStart() {
}

public void cleanAndShutdown() {

}

}

基本的扩展类都搞好了,我们该在哪里传入给框架使用呢?请看下面的单例使用

package com.silvery.plugin.validcode.jcaptcha;

import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;

/**
*
* @author shadow
* @email 124010356@qq.com
* @create 2012.04.28
*/
public class SimpleCaptchaService {

private SimpleCaptchaService() {
// nothing
}

private static ImageCaptchaService instance = null;

/**
* SimpleListSoundCaptchaEngine //还可以用声音 SpellerSoundCaptchaEngine
* SpellerSoundCaptchaEngine DefaultGimpyEngineCaptcha
* BaffleListGimpyEngineCaptcha BasicListGimpyEngineCaptcha
* DeformedBaffleListGimpyEngineCaptcha DoubleRandomListGimpyEngineCaptcha
* SimpleListImageCaptchaEngineCaptcha SimpleFishEyeEngineCaptcha
*/
static {
instance = new DefaultManageableImageCaptchaService(new MemcacheCaptchaStore(), new SimpleCaptchaEngine(), 180,
100000, 75000);
}

public static ImageCaptchaService getInstance() {
return instance;
}

public static boolean validate(String s, Object input) {
return instance.validateResponseForID(s, input);
}

}

写个servlet让我们的页面可以访问生成出验证码图片

package com.silvery.plugin.validcode.jcaptcha;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.UUID;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.octo.captcha.service.CaptchaServiceException;
import com.silvery.security.variable.Const;
import com.silvery.utils.CookieUtils;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
* jcaptcha图片生成
*
* @author shadow
* @email 124010356@qq.com
* @create 2012.04.28
*/
@SuppressWarnings("serial")
public class CaptchaServlet extends HttpServlet {

public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
}

protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
throws ServletException, IOException {

byte[] captchaChallengeAsJpeg = null;
// the output stream to render the captcha image as jpeg into
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
try {
// get the session id that will identify the generated captcha.
// the same id must be used to validate the response, the session id
// is a good candidate!
String captchaId = UUID.randomUUID().toString();
// call the ImageCaptchaService getChallenge method
BufferedImage challenge = SimpleCaptchaService.getInstance().getImageChallengeForID(captchaId,
httpServletRequest.getLocale());

// a jpeg encoder
JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
jpegEncoder.encode(challenge);
httpServletResponse.addCookie(CookieUtils.createCookie(Const.USER_MODULE_JCAPTCHA, captchaId, 1800));
} catch (IllegalArgumentException e) {
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
} catch (CaptchaServiceException e) {
httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}

captchaChallengeAsJpeg = jpegOutputStream.toByteArray();

// flush it in the response
httpServletResponse.setHeader("Cache-Control", "no-store");
httpServletResponse.setHeader("Pragma", "no-cache");
httpServletResponse.setDateHeader("Expires", 0);
httpServletResponse.setContentType("image/jpeg");
ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream();
responseOutputStream.write(captchaChallengeAsJpeg);
responseOutputStream.flush();
responseOutputStream.close();
}
}


最后我们配置下web.xml启动项目看看效果咯

<servlet>
<servlet-name>jcaptcha</servlet-name>
<servlet-class>com.silvery.plugin.validcode.jcaptcha.CaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jcaptcha</servlet-name>
<url-pattern>*.jcapt</url-pattern>
</servlet-mapping>





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐