1.项目结构
2.类的内容
2.1 Digest
package com.rtsm.zhjs.background.common.imgcode;
/**
* @author loki
* @date 2018-04-27 上午10:16
**/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.MessageDigest;
public class Digest {
private static final Logger logger = LoggerFactory.getLogger(Digest.class);
protected String algorithm;
public Digest(String alg) {
this.algorithm = alg;
}
public byte[] encode2bytes(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance(this.algorithm);
return md.digest(bytes);
} catch (Exception var3) {
logger.error("MessageDigest with {} fail", this.algorithm);
logger.error("MessageDigest fail", var3);
return null;
}
}
public byte[] encode2bytes(String data, String charset) {
if (data == null) {
return null;
} else {
try {
byte[] bytes;
if (charset == null) {
bytes = data.getBytes();
} else {
bytes = data.getBytes(charset);
}
return this.encode2bytes(bytes);
} catch (Exception var4) {
logger.error("MD5 encode fail", var4);
return null;
}
}
}
public String encode(String data, String charset, boolean lowercase) {
byte[] endata = this.encode2bytes(data, charset);
return endata == null ? null : HexCode.encode(endata, lowercase);
}
public String encode(String data, boolean lowercase) {
return this.encode(data, (String) null, lowercase);
}
public String encode(String data) {
return this.encode(data, (String) null, true);
}
public String encode(String data, String charset) {
return this.encode(data, charset, true);
}
}
2.2 HexCode
package com.rtsm.zhjs.background.common.imgcode;
/**
* @author loki
* @date 2018-04-27 上午10:18
**/
public class HexCode {
private static final char[] UPPER_HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
private static final char[] LOWER_HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
public HexCode() {
}
public static char[] encode2char(byte[] bytes, boolean lowercase) {
char[] chars = new char[bytes.length * 2];
for (int i = 0; i < chars.length; i += 2) {
byte b = bytes[i / 2];
char[] HEX_CHARS = LOWER_HEX_CHARS;
if (!lowercase) {
HEX_CHARS = UPPER_HEX_CHARS;
}
chars[i] = HEX_CHARS[b >>> 4 & 15];
chars[i + 1] = HEX_CHARS[b & 15];
}
return chars;
}
public static String encode(byte[] bytes, boolean lowercase) {
char[] endata = encode2char(bytes, lowercase);
return new String(endata);
}
public static byte[] decode(String data) {
int len = (data.length() + 1) / 2;
byte[] bytes = new byte[len];
int index = 0;
for (int i = 1; i < data.length(); i += 2) {
char h = data.charAt(i - 1);
char l = data.charAt(i);
bytes[index] = decodeByte(h, l);
++index;
}
return bytes;
}
public static byte decodeByte(char hight, char low) {
int value;
byte data;
if (hight >= 65 && hight <= 70) {
value = hight - 65 + 10;
data = (byte) (value << 4);
} else if (hight >= 97 && hight <= 102) {
value = hight - 97 + 10;
data = (byte) (value << 4);
} else {
if (hight < 48 || hight > 57) {
throw new RuntimeException();
}
value = hight - 48;
data = (byte) (value << 4);
}
if (low >= 65 && low <= 70) {
value = low - 65 + 10;
data |= (byte) value;
} else if (low >= 97 && low <= 102) {
value = low - 97 + 10;
data |= (byte) value;
} else {
if (low < 48 || low > 57) {
throw new RuntimeException();
}
value = low - 48;
data |= (byte) value;
}
return data;
}
}
2.3 ImageCode
package com.rtsm.zhjs.background.common.imgcode;
/**
* 图形验证码对象
*
* @author loki
* @date 2018-04-27 上午10:12
**/
public class ImgCode {
private String key;
private String code;
private int width = -1;
private int height = -1;
private String type = "png";
private int expired = 3600;//默认600s
public ImgCode(String code) {
this.code = code;
}
public ImgCode(String key, String code) {
super();
this.key = key;
this.code = code;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int higth) {
this.height = higth;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getExpired() {
return expired;
}
public void setExpired(int expired) {
this.expired = expired;
}
}
2.4 ImgWritter.java
2.4.1 ImageWritter
package com.rtsm.zhjs.background.common.imgcode;
import com.github.bingoohuang.patchca.background.MyCustomBackgroundFactory;
import com.github.bingoohuang.patchca.color.ColorFactory;
import com.github.bingoohuang.patchca.custom.ConfigurableCaptchaService;
import com.github.bingoohuang.patchca.filter.AbstractFilterFactory;
import com.github.bingoohuang.patchca.filter.FilterFactory;
import com.github.bingoohuang.patchca.filter.library.CurvesImageOp;
import com.github.bingoohuang.patchca.filter.library.MarbleImageOp;
import com.github.bingoohuang.patchca.filter.library.RippleImageOp;
import com.github.bingoohuang.patchca.font.RandomFontFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 图片验证码的绘制处理
* @author loki
* @date 下午3:48 2018/5/4
**/
@Slf4j
public class ImgWritter {
//验证码是否添加干扰点配置项,不配置默认为true
public static final String CONF_USE_INTERFERENCE = "true";
private static final String IMG_WIDTH="160";
private static final String IMG_HEIGHT="70";
private static final String IMG_FONT_SIZE="48";
// 初始化图片验证码的主体类
private static ConfigurableCaptchaService cs = new ConfigurableCaptchaService();
private static Random random = new Random();
static {
// 设置color的生成器
cs.setColorFactory(new ColorFactory() {
@Override
public Color getColor(int x) {
int[] c = new int[3];
int i = random.nextInt(c.length);
for (int fi = 0; fi < c.length; fi++) {
if (fi == i) {
c[fi] = random.nextInt(71);
} else {
c[fi] = random.nextInt(256);
}
}
return new Color(c[0], c[1], c[2]);
}
});
// 设置图片的绘制器
cs.setFilterFactory((FilterFactory) new SimpleRippleFilterFactory(cs.getColorFactory()));
// 设置验证码的背景
cs.setBackgroundFactory(new MyCustomBackgroundFactory());
// 获取图片的宽度
String strWidth =IMG_WIDTH;
if (StringUtils.isNumeric(strWidth)) {
cs.setWidth(Integer.parseInt(strWidth));
}
// 获取图片的高度
String strHeigth = IMG_HEIGHT;
if (StringUtils.isNumeric(strHeigth)) {
cs.setHeight(Integer.parseInt(strHeigth));
}
// 设置图片字体的大小
String strFontSize = IMG_FONT_SIZE;
if (StringUtils.isNumeric(strFontSize)) {
if (cs.getFontFactory() instanceof RandomFontFactory) {
RandomFontFactory fontFactory = (RandomFontFactory) cs.getFontFactory();
fontFactory.setMinSize(Integer.parseInt(strFontSize));
fontFactory.setMaxSize(Integer.parseInt(strFontSize));
}
}
}
/**
* 图片验证码的响应头部,设置无缓存模式
*
* @param imgCode
* @param response
*/
public static void responseHeader(ImgCode imgCode, HttpServletResponse response) {
response.setContentType("image/" + imgCode.getType());
response.setHeader("Cache-Control", "no-cache, no-store");
response.setHeader("Pragma", "no-cache");
long time = System.currentTimeMillis();
response.setDateHeader("Last-Modified", time);
response.setDateHeader("Date", time);
response.setDateHeader("Expires", time);
}
/**
* 响应回写图片验证码内容
*
* @param imgCode
* @param response
*/
public static void responseImg(ImgCode imgCode, HttpServletResponse response) {
try {
int width = imgCode.getWidth();
int height = imgCode.getHeight();
if (width < 0) {
width = cs.getWidth();
}
if (height < 0) {
height = cs.getHeight();
}
BufferedImage bufImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// 填充背景
cs.getBackgroundFactory().fillBackground(bufImage);
cs.getFontFactory().setWord(imgCode.getCode());
// 绘制验证码
cs.getTextRenderer().draw(imgCode.getCode(), bufImage, cs.getFontFactory(),
cs.getColorFactory());
// 进行模糊扭曲处理
bufImage = cs.getFilterFactory().applyFilters(bufImage);
Graphics g = bufImage.getGraphics();
if (!"false".equalsIgnoreCase(CONF_USE_INTERFERENCE)) {
// 绘制干扰点
for (int i = 0; i < 3 * height; i++) {
g.setColor(cs.getColorFactory().getColor(i));
int x = random.nextInt(width);
int y = random.nextInt(height);
g.drawOval(x, y, 0, 0);
}
}
g.dispose();
// 响应图片
ImageIO.write(bufImage, imgCode.getType(), response.getOutputStream());
} catch (Exception e) {
log.error("create image code stream fail", e);
}
}
}
class SimpleRippleFilterFactory extends AbstractFilterFactory {
public static final String CONF_USE_RIPPLE = "false";
public static final String CONF_USE_MARBLE = "false";
public static final String CONF_USE_CURVES = "false";
protected List<BufferedImageOp> filters;
// 波浪扭曲处理
protected RippleImageOp ripple = new RippleImageOp();
// 模糊处理
protected MarbleImageOp marble = new MarbleImageOp();
// 曲线处理
protected CurvesImageOp curves = new CurvesImageOp();
public void setColorFactory(ColorFactory colorFactory) {
curves.setColorFactory(colorFactory);
}
public SimpleRippleFilterFactory(ColorFactory colorFactory) {
setColorFactory(colorFactory);
}
protected List<BufferedImageOp> getPreRippleFilters() {
List<BufferedImageOp> list = new ArrayList<BufferedImageOp>();
// 检查图片验证码的模糊扭曲处理是否配置,如果配置了则设置相应的处理方式
// 验证码以波浪形式变形,默认不配置则为false
if ("true".equalsIgnoreCase(CONF_USE_RIPPLE)) {
list.add(ripple);
}
// 验证码模糊处理,默认不配置则为false
if ("true".equalsIgnoreCase(CONF_USE_MARBLE)) {
list.add(marble);
}
// //验证码是否加一条曲线,默认不配置则为false
if ("true".equalsIgnoreCase(CONF_USE_CURVES)) {
list.add(curves);
}
return list;
}
protected List<BufferedImageOp> getPostRippleFilters() {
return new ArrayList<BufferedImageOp>();
}
@Override
public List<BufferedImageOp> getFilters() {
if (filters == null) {
filters = new ArrayList<BufferedImageOp>();
filters.addAll(getPreRippleFilters());
filters.addAll(getPostRippleFilters());
}
return filters;
}
}
2.4.2
SimpleRippleFilterFactory
package com.rtsm.zhjs.background.common.imgcode;
import com.github.bingoohuang.patchca.background.MyCustomBackgroundFactory;
import com.github.bingoohuang.patchca.color.ColorFactory;
import com.github.bingoohuang.patchca.custom.ConfigurableCaptchaService;
import com.github.bingoohuang.patchca.filter.AbstractFilterFactory;
import com.github.bingoohuang.patchca.filter.FilterFactory;
import com.github.bingoohuang.patchca.filter.library.CurvesImageOp;
import com.github.bingoohuang.patchca.filter.library.MarbleImageOp;
import com.github.bingoohuang.patchca.filter.library.RippleImageOp;
import com.github.bingoohuang.patchca.font.RandomFontFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 图片验证码的绘制处理
* @author loki
* @date 下午3:48 2018/5/4
**/
@Slf4j
public class ImgWritter {
//验证码是否添加干扰点配置项,不配置默认为true
public static final String CONF_USE_INTERFERENCE = "true";
private static final String IMG_WIDTH="160";
private static final String IMG_HEIGHT="70";
private static final String IMG_FONT_SIZE="48";
// 初始化图片验证码的主体类
private static ConfigurableCaptchaService cs = new ConfigurableCaptchaService();
private static Random random = new Random();
static {
// 设置color的生成器
cs.setColorFactory(new ColorFactory() {
@Override
public Color getColor(int x) {
int[] c = new int[3];
int i = random.nextInt(c.length);
for (int fi = 0; fi < c.length; fi++) {
if (fi == i) {
c[fi] = random.nextInt(71);
} else {
c[fi] = random.nextInt(256);
}
}
return new Color(c[0], c[1], c[2]);
}
});
// 设置图片的绘制器
cs.setFilterFactory((FilterFactory) new SimpleRippleFilterFactory(cs.getColorFactory()));
// 设置验证码的背景
cs.setBackgroundFactory(new MyCustomBackgroundFactory());
// 获取图片的宽度
String strWidth =IMG_WIDTH;
if (StringUtils.isNumeric(strWidth)) {
cs.setWidth(Integer.parseInt(strWidth));
}
// 获取图片的高度
String strHeigth = IMG_HEIGHT;
if (StringUtils.isNumeric(strHeigth)) {
cs.setHeight(Integer.parseInt(strHeigth));
}
// 设置图片字体的大小
String strFontSize = IMG_FONT_SIZE;
if (StringUtils.isNumeric(strFontSize)) {
if (cs.getFontFactory() instanceof RandomFontFactory) {
RandomFontFactory fontFactory = (RandomFontFactory) cs.getFontFactory();
fontFactory.setMinSize(Integer.parseInt(strFontSize));
fontFactory.setMaxSize(Integer.parseInt(strFontSize));
}
}
}
/**
* 图片验证码的响应头部,设置无缓存模式
*
* @param imgCode
* @param response
*/
public static void responseHeader(ImgCode imgCode, HttpServletResponse response) {
response.setContentType("image/" + imgCode.getType());
response.setHeader("Cache-Control", "no-cache, no-store");
response.setHeader("Pragma", "no-cache");
long time = System.currentTimeMillis();
response.setDateHeader("Last-Modified", time);
response.setDateHeader("Date", time);
response.setDateHeader("Expires", time);
}
/**
* 响应回写图片验证码内容
*
* @param imgCode
* @param response
*/
public static void responseImg(ImgCode imgCode, HttpServletResponse response) {
try {
int width = imgCode.getWidth();
int height = imgCode.getHeight();
if (width < 0) {
width = cs.getWidth();
}
if (height < 0) {
height = cs.getHeight();
}
BufferedImage bufImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// 填充背景
cs.getBackgroundFactory().fillBackground(bufImage);
cs.getFontFactory().setWord(imgCode.getCode());
// 绘制验证码
cs.getTextRenderer().draw(imgCode.getCode(), bufImage, cs.getFontFactory(),
cs.getColorFactory());
// 进行模糊扭曲处理
bufImage = cs.getFilterFactory().applyFilters(bufImage);
Graphics g = bufImage.getGraphics();
if (!"false".equalsIgnoreCase(CONF_USE_INTERFERENCE)) {
// 绘制干扰点
for (int i = 0; i < 3 * height; i++) {
g.setColor(cs.getColorFactory().getColor(i));
int x = random.nextInt(width);
int y = random.nextInt(height);
g.drawOval(x, y, 0, 0);
}
}
g.dispose();
// 响应图片
ImageIO.write(bufImage, imgCode.getType(), response.getOutputStream());
} catch (Exception e) {
log.error("create image code stream fail", e);
}
}
}
class SimpleRippleFilterFactory extends AbstractFilterFactory {
public static final String CONF_USE_RIPPLE = "false";
public static final String CONF_USE_MARBLE = "false";
public static final String CONF_USE_CURVES = "false";
protected List<BufferedImageOp> filters;
// 波浪扭曲处理
protected RippleImageOp ripple = new RippleImageOp();
// 模糊处理
protected MarbleImageOp marble = new MarbleImageOp();
// 曲线处理
protected CurvesImageOp curves = new CurvesImageOp();
public void setColorFactory(ColorFactory colorFactory) {
curves.setColorFactory(colorFactory);
}
public SimpleRippleFilterFactory(ColorFactory colorFactory) {
setColorFactory(colorFactory);
}
protected List<BufferedImageOp> getPreRippleFilters() {
List<BufferedImageOp> list = new ArrayList<BufferedImageOp>();
// 检查图片验证码的模糊扭曲处理是否配置,如果配置了则设置相应的处理方式
// 验证码以波浪形式变形,默认不配置则为false
if ("true".equalsIgnoreCase(CONF_USE_RIPPLE)) {
list.add(ripple);
}
// 验证码模糊处理,默认不配置则为false
if ("true".equalsIgnoreCase(CONF_USE_MARBLE)) {
list.add(marble);
}
// //验证码是否加一条曲线,默认不配置则为false
if ("true".equalsIgnoreCase(CONF_USE_CURVES)) {
list.add(curves);
}
return list;
}
protected List<BufferedImageOp> getPostRippleFilters() {
return new ArrayList<BufferedImageOp>();
}
@Override
public List<BufferedImageOp> getFilters() {
if (filters == null) {
filters = new ArrayList<BufferedImageOp>();
filters.addAll(getPreRippleFilters());
filters.addAll(getPostRippleFilters());
}
return filters;
}
}
2.5 Md5
package com.rtsm.zhjs.background.common.imgcode;
/**
* @author loki
* @date 2018-04-27 上午10:15
**/
public class Md5 {
private static final Digest digest = new Digest("MD5");
public Md5() {
}
public static byte[] encode2bytes(byte[] bytes) {
return digest.encode2bytes(bytes);
}
public static byte[] encode2bytes(String data, String charset) {
return digest.encode2bytes(data, charset);
}
public static String encode(String data, String charset, boolean lowercase) {
return digest.encode(data, charset, lowercase);
}
public static String encode(String data, boolean lowercase) {
return encode(data, (String) null, lowercase);
}
public static String encode(String data) {
return encode(data, (String) null, true);
}
public static String encode(String data, String charset) {
return encode(data, charset, true);
}
}
3. ImgCodeService
package com.rtsm.zhjs.background.modules.system.service;
import com.ace.cache.EnableAceCache;
import com.ace.cache.service.IRedisService;
import com.rtsm.zhjs.background.common.imgcode.ImgCode;
import com.rtsm.zhjs.background.common.imgcode.Md5;
import com.rtsm.zhjs.background.util.MapUtils;
import com.rtsm.zhjs.background.util.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author loki
* @date 2018-04-27 上午10:09
**/
@PropertySource({"classpath:application.yml"})
@Component
@EnableAceCache
@Slf4j
public class ImgCodeService {
// 配置文件未配置时默认使用的验证码列表
private static String[] DEFAULT_CHARS = {"A", "B", "C", "D", "E", "F", "G", "H", "J", "K",
"L", "M", "P", "Q", "R", "S", "T", "U", "W", "X", "Y", "2", "3", "4", "5", "6", "7",
"8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "k", "m", "p", "q", "r", "s", "t",
"u", "w", "x", "y"};
private static final String IMG_SIGN_KEY = "1f905d35378e4a5d89aeb126faf8baf9";
private static final String IMG_CACHE_KEY_PREFFIX = "imgcode_";
private static final int IMG_CODE_EXPIRED = 36000;//二维码过期时间 默认为10分钟
private static String[] IMG_CHARS;
@Autowired
private IRedisService iRedisService;
/**
* 获取验证码字符集列表,这里只生成数字加英文(不区分大小写)
*
* @return
*/
private String[] getImgCodeChars() {
if (IMG_CHARS != null) {
return IMG_CHARS;
}
return DEFAULT_CHARS;
}
/**
* 生成图片验证码内容
*
* @return
*/
public String generateImgCode(int length) {
if (length < 0) {
log.info("图形验证码长度不能为0");
}
String[] verifyCodes = getImgCodeChars();
StringBuilder sb = new StringBuilder(length);
int rand;
// Random random = new Random();
// 随机生成索引获取验证码字符
for (int i = 0; i < length; i++) {
// rand = random.nextInt(length);
rand = Integer.valueOf(String.valueOf(Math.round(Math.random()
* (verifyCodes.length - 1))));
sb.append(verifyCodes[rand]);
}
return sb.toString();
}
/**
* 如果key存在则使用同一个key刷新验证码内容
*
* @param key
* @param value
* @param expired
* @return
*/
public boolean refreshImgCode(String key, String value, int expired) {
if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
if (iRedisService.exists(key)) {
String result = iRedisService.set(key, value, expired);
if (StringUtils.isNotBlank(result) && "OK".equals(result)) {
return true;
}
}
}
return false;
}
/**
* 保存验证码
*
* @param key
* @param value
* @param expired
* @return
*/
public String saveImgCode(String key, String value, int expired) {
if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
log.info("保存图形验证码");
return iRedisService.set(IMG_CACHE_KEY_PREFFIX + key, value, expired);
}
return "";
}
/**
* 生成图片验证码
*
* @param length
* @param client_ip
* @return
*/
public ImgCode generate(int length, String client_ip, String existKey) {
return generate(length, client_ip, IMG_CODE_EXPIRED, existKey);
}
/**
* 生成图片验证码
*
* @param length
* @param client_ip
* @param expired
* @return
*/
public ImgCode generate(int length, String client_ip, int expired, String existKey) {
// 生成验证码内容
String imgCode = generateImgCode(length);
long time = System.currentTimeMillis();
// 拼接验证码缓存保存的内容,除验证码外还保存时间、IP、和签名
StringBuilder content = new StringBuilder(32);
content.append("img_code=").append(imgCode).append("&time=").append(time).append("&ip=")
.append(client_ip);
String sign = Md5.encode(content.toString() + IMG_SIGN_KEY);
content.append("&sign=").append(sign);
String value = content.toString();
String key = existKey;
// 如果key存在则刷新,不存在则添加
if (StringUtils.isBlank(key) || !refreshImgCode(key, value, expired)) {
// uuid生成key
key = UUIDUtils.generateUuid();
// 写入缓存,一定要有过期时间,建议验证码过期时间为10分钟
if (!"OK".equals(saveImgCode(key, value, expired))) {
log.info("保存图形验证码失败");
}
}
// 返回
ImgCode imgInfo = new ImgCode(key, imgCode);
imgInfo.setExpired(expired);
return imgInfo;
}
/**
* 检查验证码是否正确
*
* @param imgInfo
* @param client_ip
* @return
*/
public boolean checkImgCode(ImgCode imgInfo, String client_ip, boolean isDel) {
String key = IMG_CACHE_KEY_PREFFIX + imgInfo.getKey();
log.info("-------------key:" + key);
// 获取缓存中的验证码
String strSvcInfo = iRedisService.get(key);
if (StringUtils.isBlank(strSvcInfo)) {
log.info("img key[{}] cache value is empty", key);
return false;
}
// 检验签名,先截取sign之前的字段
int pos = strSvcInfo.lastIndexOf("&sign=");
if (pos < 0) {
log.info("img key[{}] cache value is empty", key);
return false;
}
String subStr = strSvcInfo.substring(0, pos);
String sign = Md5.encode(subStr + IMG_SIGN_KEY);
if (!sign.equals(strSvcInfo.substring(pos + 6))) {
log.info("img key[{}] cache value sign is invalid", key);
return false;
}
// 获取缓存的数据,校验验证码是否正确
Map<String, String> imgSvcInfo = MapUtils.str2Map(strSvcInfo);
String imgCode = imgSvcInfo.get("img_code");
if (!imgInfo.getCode().equalsIgnoreCase(imgCode)) {
log.info("img key[{}] code incorrect.cache code={},request code={}",
key, imgCode, imgInfo.getCode());
return false;
}
// 如果ip不为null,则验证ip是否正确,因为正常情况生成验证码和使用验证码应该是同一个IP请求
if (client_ip != null) {
String ip = imgSvcInfo.get("ip");
if (!client_ip.equals(ip)) {
log.error("img key[{}] ip incorrect", key);
return false;
}
}
// 验证成功后删除redis缓存的信息
if (!isDel) {
return true;
}
iRedisService.del(key);
return true;
}
}
4.html图片码对应文件
点击二维码的时候刷新
5.js对应调用
//从cookie中获取图片码,将后台请求图片接口的路径放入到html的src中即可,imageKey为后台往cookie中塞入的值
var imageKey = document.cookie;
6.Controller中的代码
/**
* 获取图形验证码
*
* @author loki
* @date 11:24 PM 2019/3/20
**/
@GetMapping(value = "/imgCode/{imgk}")
@ResponseBody
public void getImageCode(HttpServletRequest request, HttpServletResponse response, @PathVariable String imgk) {
ImgCode imgCode = sysYhxxService.getImgCode(ClientUtil.getClientIp(request), imgk);
ImgWritter.responseHeader(imgCode, response);
Cookie cookie = new Cookie("imgk",imgCode.getKey());
cookie.setMaxAge(imgCode.getExpired());
cookie.setPath("/");
response.addCookie(cookie);
ImgWritter.responseImg(imgCode, response);
}
图片码生成了以后放入到cookie中了,所以在js中直接src(接口访问路径)就可以显示出图片码样式。
存入redis中的imgk也可以在js中获取。
当页面加载的时候就去Controller中获取图片码,并在js中获取imgk,请求登陆的时候传到Controller中,在从redis中根据key获取到对应的imgCode,校验用户输入的是否正确