在spring security中,可以结合jcaptcha进行使用,具体方法如下:
1.java类如下:
package com.spring.security.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验证码的样式.
*/
public class GMailEngine extends ListImageCaptchaEngine {
@Override
protected void buildInitialFactories() {
// 图片和字体大小设置
int minWordLength = 4;
int maxWordLength = 5;
int fontSize = 20;
int imageWidth = 100;
int imageHeight = 36;
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));
}
}
过滤器如下:
package com.spring.security.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.apache.log4j.Logger;
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)
*
*/
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";
protected static Logger logger = Logger.getLogger("service");
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();
// 符合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);
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 {
if(out!=null){
out.close();
}
}
}
/**
* 验证验证码.
*/
protected boolean validateCaptchaChallenge(final HttpServletRequest request) {
try {
String captchaID = request.getSession().getId();
String challengeResponse = request
.getParameter(captchaParamterName);
// 自动通过值存在时,检验输入值是否等于自动通过值
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 {
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");
}
}
web.xml 配置如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>springSecurityIII</display-name> <!--******************************** --> <!--*******log4j日志信息的配置****** --> <!--******************************* --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j.xml</param-value> </context-param> <!--Spring默认刷新Log4j配置文件的间隔,单位为millisecond,可以不设置 --> <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>60000</param-value> </context-param> <!--******************************** --> <!--*******spring bean的配置******** --> <!--******************************* --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <!--******************************** --> <!--*******字符集 过滤器************ --> <!--******************************* --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--******************************** --> <!--*******session的配置************ --> <!--******************************* --> <session-config> <session-timeout>30</session-timeout> </session-config> <filter> <filter-name>jcaptchaFilter</filter-name> <filter-class>com.spring.security.jcaptcha.JCaptchaFilter</filter-class> <init-param> <param-name>failureUrl</param-name> <param-value>/login.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>jcaptchaFilter</filter-name> <url-pattern>/jcaptcha.jpg</url-pattern> </filter-mapping> <filter-mapping> <filter-name>jcaptchaFilter</filter-name> <url-pattern>/j_spring_security_check</url-pattern> </filter-mapping> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> </listener> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
login.jsp
<%@ include file="/common/taglibs.jsp"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登 录</title>
<script type="text/javascript">
/*==============================================
* refreash the captcha to general new picture
*==============================================*/
function refreshCaptcha() {
$('#captchaImg').hide().attr(
'src',
'<c:url value="/jcaptcha.jpg"/>' + '?' + Math.floor(Math.random() * 100)).fadeIn();
}
</script>
</head>
<body>
<center>
<div class="login-error">
${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}
</div>
<form action="${pageContext.request.contextPath}/j_spring_security_check" method="post">
<table style="width: 60%">
<tr>
<td>用户名:</td>
<td>
<input class = "login-smallInput" type='text' name='j_username'/>
</td>
</tr>
<tr>
<td>密 码:</td>
<td>
<input class = "login-smallInput" type='password' name='j_password' />
</td>
</tr>
<tr>
<td>验证码:</td>
<td>
<input type='text' name='j_captcha' size="5"/>
<img id="captchaImg" style="vertical-align:middle" src="<c:url value="/jcaptcha.jpg"/>" />
<a href="javascript:refreshCaptcha()">看不清楚换一张</a>
</td>
</tr>
<tr>
<td>
<input id="_spring_security_remember_me" name="_spring_security_remember_me" type="checkbox"/>
</td>
<td>
<label for="_spring_security_remember_me">Remember Me?</label>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="submit" value="登录" />
</td>
</tr>
</table>
</form>
</center>
</body>
</html>