/**
* 生成图形验证码
*/
@RequestMapping("captcha.jpg")
public void captcha(HttpServletRequest request, HttpServletResponse response) {
dreamCaptcha.generate(request, response);
}
/**
* 验证码验证
*/
dreamCaptcha.validate(request, response, auth)
package com.ssy.test.utils;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.QuadCurve2D;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
/**
* 生成验证码
* @author ForeignStudent
*/
public class CaptchaUtils {
// 默认的验证码大小
private static final int WIDTH = 108, HEIGHT = 40, CODE_SIZE = 4;
// 验证码随机字符数组
protected static final char[] charArray = "3456789ABCDEFGHJKMNPQRSTUVWXY".toCharArray();
// 验证码字体
private static final Font[] RANDOM_FONT = new Font[] { new Font("nyala", Font.BOLD, 38),
new Font("Arial", Font.BOLD, 32), new Font("Bell MT", Font.BOLD, 32),
new Font("Credit valley", Font.BOLD, 34), new Font("Impact", Font.BOLD, 32),
new Font(Font.MONOSPACED, Font.BOLD, 40) };
/**
* 生成验证码
*/
static void generate(HttpServletResponse response, String vCode) {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
ServletOutputStream sos = null;
try {
drawGraphic(image, vCode);
sos = response.getOutputStream();
ImageIO.write(image, "JPEG", sos);
sos.flush();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
IOUtils.closeQuietly(sos);
}
}
// 生成随机类
private static final Random RANDOM = new Random();
/**
* 生成验证码字符串
*
* @return 验证码字符串
*/
static String generateCode() {
int count = CODE_SIZE;
char[] buffer = new char[count];
for (int i = 0; i < count; i++) {
buffer[i] = charArray[RANDOM.nextInt(charArray.length)];
}
return new String(buffer);
}
private static void drawGraphic(BufferedImage image, String code) {
// 获取图形上下文
Graphics2D g = image.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
// 图形抗锯齿
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 字体抗锯齿
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// 设定背景色,淡色
g.setColor(getRandColor(210, 250));
g.fillRect(0, 0, WIDTH, HEIGHT);
// 画小字符背景
Color color = null;
for (int i = 0; i < 20; i++) {
color = getRandColor(120, 200);
g.setColor(color);
String rand = String.valueOf(charArray[RANDOM.nextInt(charArray.length)]);
g.drawString(rand, RANDOM.nextInt(WIDTH), RANDOM.nextInt(HEIGHT));
color = null;
}
// 取随机产生的认证码(4位数字)
char[] buffer = code.toCharArray();
for (int i = 0; i < buffer.length; i++) {
char _code = buffer[i];
// 旋转度数 最好小于45度
int degree = RANDOM.nextInt(28);
if (i % 2 == 0) {
degree = degree * (-1);
}
// 定义坐标
int x = 22 * i, y = 21;
// 旋转区域
g.rotate(Math.toRadians(degree), x, y);
// 设定字体颜色
color = getRandColor(20, 130);
g.setColor(color);
// 设定字体,每次随机
g.setFont(RANDOM_FONT[RANDOM.nextInt(RANDOM_FONT.length)]);
// 将认证码显示到图象中
g.drawString("" + _code, x + 8, y + 10);
// 旋转之后,必须旋转回来
g.rotate(-Math.toRadians(degree), x, y);
}
// 图片中间曲线,使用上面缓存的color
g.setColor(color);
// width是线宽,float型
BasicStroke bs = new BasicStroke(3);
g.setStroke(bs);
// 画出曲线
QuadCurve2D.Double curve = new QuadCurve2D.Double(0d, RANDOM.nextInt(HEIGHT - 8) + 4, WIDTH / 2, HEIGHT / 2,
WIDTH, RANDOM.nextInt(HEIGHT - 8) + 4);
g.draw(curve);
// 销毁图像
g.dispose();
}
/**
* 给定范围获得随机颜色
*/
private static Color getRandColor(int fc, int bc) {
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + RANDOM.nextInt(bc - fc);
int g = fc + RANDOM.nextInt(bc - fc);
int b = fc + RANDOM.nextInt(bc - fc);
return new Color(r, g, b);
}
}
package com.conferencerooms.utils.verifycode;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import com.conferencerooms.utils.StringUtils;
/**
* 验证码验证
* @author ForeignStudent
*/
public class DreamCaptcha implements InitializingBean {
private final static Logger logger = LogManager.getLogger(DreamCaptcha.class);
private static final String DEFAULT_COOKIE_NAME = "dream-captcha";
private final static String DEFAULT_CHACHE_NAME = "dreamCaptchaCache";
private final static int DEFAULT_MAX_AGE = -1; // cookie超时默认为session会话状态
private CacheManager cacheManager;
private String cacheName;
private String cookieName;
private Cache<String, String> dreamCaptchaCache;
public DreamCaptcha() {
this.cacheName = DEFAULT_CHACHE_NAME;
this.cookieName = DEFAULT_COOKIE_NAME;
}
public DreamCaptcha(CacheManager cacheManager) {
this();
this.cacheManager = cacheManager;
}
public CacheManager getCacheManager() {
return cacheManager;
}
public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
public String getCacheName() {
return cacheName;
}
public void setCacheName(String cacheName) {
this.cacheName = cacheName;
}
public String getCookieName() {
return cookieName;
}
public void setCookieName(String cookieName) {
this.cookieName = cookieName;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(cacheManager, "cacheManager must not be null!");
Assert.hasText(cacheName, "cacheName must not be empty!");
Assert.hasText(cookieName, "cookieName must not be empty!");
this.dreamCaptchaCache = cacheManager.getCache(cacheName);
}
/**
* 生成验证码
*/
public void generate(HttpServletRequest request, HttpServletResponse response) {
// 先检查cookie的uuid是否存在
String cookieValue = getCookieValue(request, cookieName);
boolean hasCookie = true;
if (StringUtils.isBlank(cookieValue)) {
hasCookie = false;
cookieValue = StringUtils.getUUId();
}
// 转成大写重要
String captchaCode = CaptchaUtils.generateCode().toUpperCase();
// 不存在cookie时设置cookie
if (!hasCookie) {
setCookie(response, cookieName, cookieValue, DEFAULT_MAX_AGE);
}
// 生成验证码
CaptchaUtils.generate(response, captchaCode);
dreamCaptchaCache.put(cookieValue, captchaCode);
}
/**
* 仅能验证一次,验证后立即删除
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param userInputCaptcha 用户输入的验证码
* @return 验证通过返回 true, 否则返回 false
*/
public boolean validate(HttpServletRequest request, HttpServletResponse response, String userInputCaptcha) {
if (logger.isDebugEnabled()) {
logger.debug("validate captcha userInputCaptcha is " + userInputCaptcha);
}
String cookieValue = getCookieValue(request, cookieName);
if (StringUtils.isBlank(cookieValue)) {
return false;
}
String captchaCode = dreamCaptchaCache.get(cookieValue);
if (StringUtils.isBlank(captchaCode)) {
return false;
}
// 转成大写重要
userInputCaptcha = userInputCaptcha.toUpperCase();
boolean result = userInputCaptcha.equals(captchaCode);
if (result) {
dreamCaptchaCache.remove(cookieValue);
removeCookie(response, cookieName);
}
return result;
}
/**
* 读取cookie
*
* @param request
* @param key
* @return
*/
public static String getCookieValue(HttpServletRequest request, String name) {
Cookie cookie = org.springframework.web.util.WebUtils.getCookie(request, name);
return cookie != null ? cookie.getValue() : null;
}
/**
* 设置cookie
*
* @param response
* @param name
* @param value
* @param maxAgeInSeconds
*/
public static void setCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
Cookie cookie = new Cookie(name, value);
cookie.setPath("/");
cookie.setMaxAge(maxAgeInSeconds);
cookie.setHttpOnly(true);
response.addCookie(cookie);
}
/**
* 清除 某个指定的cookie
*
* @param response
* @param key
*/
public static void removeCookie(HttpServletResponse response, String key) {
setCookie(response, key, null, 0);
}
/**
* 判断是否ajax请求 spring ajax 返回含有 ResponseBody 或者 RestController注解
*
* @param handlerMethod HandlerMethod
* @return 是否ajax请求
*/
public static boolean isAjax(HandlerMethod handlerMethod) {
ResponseBody responseBody = handlerMethod.getMethodAnnotation(ResponseBody.class);
if (null != responseBody) {
return true;
}
RestController restAnnotation = handlerMethod.getBeanType().getAnnotation(RestController.class);
if (null != restAnnotation) {
return true;
}
return false;
}
}
<!-- 验证码 -->
<bean class="com.conferencerooms.utils.verifycode.DreamCaptcha">
<property name="cacheManager" ref="shiroCacheManager"/>
<property name="cacheName" value="halfHour"/>
</bean>