JCaptcha是一个验证码的框架.
照着白衣的springside3的例子鼓捣了半天,弄出来感觉不复杂但是很有用.
不多说,放货.
创建一个jcaptcha包
在jcaptcha包里创建2个类:GMailEngine 和 JCaptchaFilter
GMailEngine :是JCaptcha验证码图片生成引擎,仿照JCaptcha2.0编写类似GMail验证码的样式.
JCaptchaFilter:是针对 JCaptcha 专门的过滤器(Filter).
另外 remember-me 这个功能我测试用 把系统时间更改下,确实是可以实现在两周之类免登录.
包结构
GMailEngine.java
package com.sjax.myapp.jcaptcha;
import java.awt.Color;
import java.awt.Font;
import java.awt.image.ImageFilter;
import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator;
import com.octo.captcha.component.image.color.RandomListColorGenerator;
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.TextDecorator;
import com.octo.captcha.component.image.wordtoimage.DeformedComposedWordToImage;
import com.octo.captcha.component.image.wordtoimage.WordToImage;
import com.octo.captcha.component.word.FileDictionary;
import com.octo.captcha.component.word.wordgenerator.ComposeDictionaryWordGenerator;
import com.octo.captcha.component.word.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import com.octo.captcha.image.gimpy.GimpyFactory;
/**
* JCaptcha验证码图片生成引擎,仿照JCaptcha2.0编写类似GMail验证码的样式.
*
* @author liukai
*
*/
public class GMailEngine extends ListImageCaptchaEngine {
@Override
protected void buildInitialFactories() {
int minWordLength = 4;
int maxWordLength = 5;
int fontSize = 50;
int imageWidth = 250;
int imageHeight = 100;
WordGenerator dictionnaryWords = new ComposeDictionaryWordGenerator(
new FileDictionary("toddlist"));
// word2image components
TextPaster randomPaster = new DecoratedRandomTextPaster(minWordLength,
maxWordLength, new RandomListColorGenerator(new Color[] {
new Color(23, 170, 27), new Color(220, 34, 11),
new Color(23, 67, 172) }), new TextDecorator[] {});
BackgroundGenerator background = new UniColorBackgroundGenerator(
imageWidth, imageHeight, Color.white);
FontGenerator font = new RandomFontGenerator(fontSize, fontSize,
new Font[] { new Font("nyala", Font.BOLD, fontSize),
new Font("Bell MT", Font.PLAIN, fontSize),
new Font("Credit valley", Font.BOLD, fontSize) });
ImageDeformation postDef = new ImageDeformationByFilters(
new ImageFilter[] {});
ImageDeformation backDef = new ImageDeformationByFilters(
new ImageFilter[] {});
ImageDeformation textDef = new ImageDeformationByFilters(
new ImageFilter[] {});
WordToImage word2image = new DeformedComposedWordToImage(font,
background, randomPaster, backDef, textDef, postDef);
addFactory(new GimpyFactory(dictionnaryWords, word2image));
}
}
JCaptchaFilter.java
package com.sjax.myapp.jcaptcha;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.octo.captcha.service.CaptchaService;
import com.octo.captcha.service.CaptchaServiceException;
/**
* 针对 JCaptcha 专门的过滤器(Filter)
* @author liukai
*
*/
public class JCaptchaFilter implements Filter {
//web.xml中的参数名定义
public static final String PARAM_CAPTCHA_PARAMTER_NAME = "captchaParamterName";
public static final String PARAM_CAPTCHA_SERVICE_ID = "captchaServiceId";
public static final String PARAM_FILTER_PROCESSES_URL = "filterProcessesUrl";
public static final String PARAM_FAILURE_URL = "failureUrl";
public static final String PARAM_AUTO_PASS_VALUE = "autoPassValue";
//默认值定义
public static final String DEFAULT_FILTER_PROCESSES_URL = "/j_spring_security_check";
public static final String DEFAULT_CAPTCHA_SERVICE_ID = "captchaService";
public static final String DEFAULT_CAPTCHA_PARAMTER_NAME = "j_captcha";
private static Logger logger = LoggerFactory.getLogger(JCaptchaFilter.class);
private String failureUrl;
private String filterProcessesUrl = DEFAULT_FILTER_PROCESSES_URL;
private String captchaServiceId = DEFAULT_CAPTCHA_SERVICE_ID;
private String captchaParamterName = DEFAULT_CAPTCHA_PARAMTER_NAME;
private String autoPassValue;
private CaptchaService captchaService;
/**
* Filter回调初始化函数.
*/
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
initParameters(filterConfig);
initCaptchaService(filterConfig);
}
public void doFilter(ServletRequest theRequest, ServletResponse theResponse,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) theRequest;
HttpServletResponse response = (HttpServletResponse) theResponse;
String servletPath = request.getServletPath();
logger.info("servletPath:"+servletPath);
//符合filterProcessesUrl为验证处理请求,其余为生成验证图片请求.
if (StringUtils.startsWith(servletPath, filterProcessesUrl)) {
boolean validated = validateCaptchaChallenge(request);
if (validated) {
chain.doFilter(request, response);
} else {
redirectFailureUrl(request, response);
}
} else {
genernateCaptchaImage(request, response);
}
}
/**
* Filter回调退出函数.
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* 初始化web.xml中定义的filter init-param.
*/
protected void initParameters(final FilterConfig fConfig) {
if (StringUtils.isBlank(fConfig.getInitParameter(PARAM_FAILURE_URL))) {
throw new IllegalArgumentException("CaptchaFilter缺少failureUrl参数");
}
failureUrl = fConfig.getInitParameter(PARAM_FAILURE_URL);
logger.info("failureUrl:"+failureUrl);
if (StringUtils.isNotBlank(fConfig.getInitParameter(PARAM_FILTER_PROCESSES_URL))) {
filterProcessesUrl = fConfig.getInitParameter(PARAM_FILTER_PROCESSES_URL);
}
if (StringUtils.isNotBlank(fConfig.getInitParameter(PARAM_CAPTCHA_SERVICE_ID))) {
captchaServiceId = fConfig.getInitParameter(PARAM_CAPTCHA_SERVICE_ID);
}
if (StringUtils.isNotBlank(fConfig.getInitParameter(PARAM_CAPTCHA_PARAMTER_NAME))) {
captchaParamterName = fConfig.getInitParameter(PARAM_CAPTCHA_PARAMTER_NAME);
}
if (StringUtils.isNotBlank(fConfig.getInitParameter(PARAM_AUTO_PASS_VALUE))) {
autoPassValue = fConfig.getInitParameter(PARAM_AUTO_PASS_VALUE);
}
}
/**
* 从ApplicatonContext获取CaptchaService实例.
*/
protected void initCaptchaService(final FilterConfig fConfig) {
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(fConfig.getServletContext());
captchaService = (CaptchaService) context.getBean(captchaServiceId);
}
/**
* 生成验证码图片.
*/
protected void genernateCaptchaImage(final HttpServletRequest request, final HttpServletResponse response)
throws IOException {
setDisableCacheHeader(response);
response.setContentType("image/jpeg");
ServletOutputStream out = response.getOutputStream();
try {
String captchaId = request.getSession(true).getId();
BufferedImage challenge = (BufferedImage) captchaService.getChallengeForID(captchaId, request.getLocale());
ImageIO.write(challenge, "jpg", out);
out.flush();
} catch (CaptchaServiceException e) {
logger.error(e.getMessage(), e);
} finally {
out.close();
}
}
/**
* 验证验证码.
*/
protected boolean validateCaptchaChallenge(final HttpServletRequest request) {
try {
String captchaID = request.getSession().getId();
logger.info("captchaID:"+captchaID);
String challengeResponse = request.getParameter(captchaParamterName);
logger.info("challengeResponse:"+challengeResponse);
//自动通过值存在时,检验输入值是否等于自动通过值
if (StringUtils.isNotBlank(autoPassValue) && autoPassValue.equals(challengeResponse)) {
return true;
}
return captchaService.validateResponseForID(captchaID, challengeResponse);
} catch (CaptchaServiceException e) {
logger.error(e.getMessage(), e);
return false;
}
}
/**
* 跳转到失败页面.
*
* 可在子类进行扩展, 比如在session中放入SpringSecurity的Exception.
*/
protected void redirectFailureUrl(final HttpServletRequest request, final HttpServletResponse response)
throws IOException {
logger.info("跳转到失败页面:"+request.getContextPath()+failureUrl);
response.sendRedirect(request.getContextPath() + failureUrl);
}
/**
* 设置禁止客户端缓存的Header.
*/
public static void setDisableCacheHeader(HttpServletResponse response) {
//Http 1.0 header
response.setDateHeader("Expires", 1L);
response.addHeader("Pragma", "no-cache");
//Http 1.1 header
response.setHeader("Cache-Control", "no-cache, no-store, max-age=0");
}
}
然后在springsecurity的配置文件里添加,直接把文件全部拷贝过来 JCaptcha相关的配置就一段,在最下面.
application-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:s="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"
default-lazy-init="true">
<s:authentication-manager>
<s:authentication-provider>
<s:password-encoder hash="md5" />
<s:jdbc-user-service data-source-ref="dataSource" />
</s:authentication-provider>
</s:authentication-manager>
<!-- 导入自定义的springsecurity国际化文件 -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages_zh_CN" />
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver" />
<s:http auto-config="true">
<!-- 指定登录页面 -->
<s:form-login login-page="/login.jsp" />
<s:logout logout-success-url="/login.jsp" />
<!-- 对登录页面不进行拦截,这个页面也许带有参数 -->
<s:intercept-url pattern="/login.jsp*" filters="none" />
<s:intercept-url pattern="/resources/**" filters="none" />
<s:remember-me />
<!-- 会话配置管理 -->
<s:session-management invalid-session-url="/login.jsp">
<!-- 只允许一个人登陆,并且第二个人登陆不了 -->
<s:concurrency-control max-sessions="1"
error-if-maximum-exceeded="true" />
</s:session-management>
</s:http>
<!-- 启动annotation -->
<s:global-method-security secured-annotations="enabled" />
<!-- Jcaptcha相关的配置 -->
<bean id="captchaService"
class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService">
<property name="captchaEngine">
<bean class="com.sjax.myapp.jcaptcha.GMailEngine" />
</property>
<!-- 默认生成的图片180秒过期 , 可另行设置
<property name="minGuarantedStorageDelayInSeconds" value="180" />
-->
</bean>
</beans>
然后是web.xml 这就不把所有的配置列出来 ,只列出和JCaptcha相关的东西
web.xml
<!-- JCaptcha`s filter -->
<filter>
<filter-name>jcaptchaFilter</filter-name>
<filter-class>com.sjax.myapp.jcaptcha.JCaptchaFilter</filter-class>
<init-param>
<param-name>failureUrl</param-name>
<param-value>/login.jsp</param-value>
</init-param>
</filter>
<!-- jcaptcha图片生成URL. -->
<filter-mapping>
<filter-name>jcaptchaFilter</filter-name>
<url-pattern>/jcaptcha.jpg</url-pattern>
</filter-mapping>
<!-- jcaptcha登录表单处理URL.
必须放在springSecurityFilter的filter-mapping定义之前 -->
<filter-mapping>
<filter-name>jcaptchaFilter</filter-name>
<url-pattern>/j_spring_security_check</url-pattern>
</filter-mapping>
最后就是JSP页面了
login.jsp
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ include file="/common/taglibs.jsp"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Login</title>
<%@ include file="/common/meta.jsp"%>
<link href="<c:url value="/resources/css/screen.css" />"
rel="stylesheet" type="text/css" />
<link href="<c:url value="/resources/css/ie.css" />" rel="stylesheet"
type="text/css" />
<script type="text/javascript"
src="<c:url value="/resources/jquery/1.4/jquery.js" />">
</script>
</head>
<body>
<div class="container">
<%@ include file="/common/header.jsp"%>
<div id="content">
<div class="span-24 last">
<h3>
用户登录
</h3>
<div class="error">
${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message }
</div>
<form id="loginForm" style="margin-top: 1em;"
action="<c:url value="/j_spring_security_check" />" method="post"">
<table class="noborder">
<tr>
<td>
<label for="username">
用户名:
</label>
</td>
<td>
<input type="text" name="j_username" class="required" />
</td>
<td rowspan="3">
<img id="captchaImg" src="<c:url value="/jcaptcha.jpg"/>" />
</td>
</tr>
<tr>
<td>
<label for="password">
密码:
</label>
</td>
<td>
<input type="password" name="j_password" class="required">
</td>
</tr>
<tr>
<td>
<label for="j_captcha">
验证码:
</label>
</td>
<td>
<input type='text' name='j_captcha' class="required" size='5' />
</td>
</tr>
<tr>
<td colspan='3'>
<input type="checkbox" name="_spring_security_remember_me" />
两周内记住我
<span style="margin-left: 25px"><a
href="javascript:refreshCaptcha()">看不清楚换一张</a>
</span>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" class="button" value="登录">
</td>
</tr>
</table>
</form>
</div>
</div>
<%@ include file="/common/footer.jsp"%>
</div>
</body>
<script type="text/javascript">
function refreshCaptcha() {
$('#captchaImg').hide().attr(
'src',
'<c:url value="/jcaptcha.jpg"/>' + '?' + Math
.floor(Math.random() * 100)).fadeIn();
}
</script>
</html>
我的开发环境是STS+tomcat6.29,工程是maven项目.框架用的spring3.0.5
效果图1.
效果图2.
BTW:因为是maven项目,所以自己要配好maven路径之类的.然后install下就行了.
如果实在不喜欢或者不会用maven,源码下下来, 照着拷贝也行的.
注意要加上JCaptcha的包还有commons-lang包
其它的spring3 springsecurity3之类的包就不多说了 打开pom.xml一个一个的看吧.