前言
spring security实现json请求的图形验证码
思路
基础实现:
我这边是参考的朱古力大佬的代码https://github.com/wuyouzhuguli/SpringAll/tree/master/36.Spring-Security-ValidateCode
直接用。
但是,他这个是适用于表单请求的。
为什么这么说呢?主要在于这一行:
获取验证码的时候,如果是表单提交,这里是可以正常获取,下面流程继续跑,是可以的。
但是如果是json请求,那么久需要从servletWebRequest里面通过流去获取传的验证码了。
但是,流里面的参数只能使用一次,这里使用了,到userDetailService,验证用户账号密码的时候,就会获取不到参数了。
具体原因,以及示例可以参考这里:https://blog.csdn.net/s1441101265/article/details/113180129
解决办法
无意间看到这篇文章:https://github.com/liuyatao/spring_security_verifycode
这一块代码:
看到他是在这里验证的。然后我看了下代码,发现这里是在验证用户登录userDetailsService之前的逻辑。
所以我也在这里调用了下验证图形验证码的方法:
ValidateCodeUtil.checkImageCode(request, authenticationBean.getImageCode());
ValidateCodeUtil
import com.website.server.system.component.security.image.bean.ImageCode;
import com.website.server.system.component.security.image.exception.ValidateCodeException;
import org.apache.commons.lang.StringUtils;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.context.request.ServletWebRequest;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* @author :qilong sun
* @date :Created in 2021/1/25 14:36
* @description:图片验证码工具类
* @modified By:
* @version: V1.0$
*/
public class ValidateCodeUtil {
/**
* 图形验证码存储在session中的key
*/
public final static String SESSION_KEY_IMAGE_CODE = "SESSION_KEY_IMAGE_CODE";
/**
* 验证图片二维码
*
* @param request
* @param imageCode
*/
public static void checkImageCode(HttpServletRequest request, String imageCode) {
// 获取sessionStrategy
SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
// 获取sessionStrategy中 的imageCode对象
ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(new ServletWebRequest(request), ValidateCodeUtil.SESSION_KEY_IMAGE_CODE);
if (StringUtils.isBlank(imageCode)) {
throw new ValidateCodeException("验证码不能为空!");
}
if (codeInSession == null) {
throw new ValidateCodeException("验证码不存在!");
}
if (codeInSession.isExpire()) {
sessionStrategy.removeAttribute(new ServletWebRequest(request), ValidateCodeUtil.SESSION_KEY_IMAGE_CODE);
throw new ValidateCodeException("验证码已过期!");
}
if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), imageCode)) {
throw new ValidateCodeException("验证码不正确!");
}
sessionStrategy.removeAttribute(new ServletWebRequest(request), ValidateCodeUtil.SESSION_KEY_IMAGE_CODE);
}
/**
* 创建image验证码
*
* @return
*/
public static ImageCode createImageCode() {
/**
* 验证码图片宽度
*/
int width = 100;
/**
* 验证码图片长度
*/
int height = 36;
/**
* 验证码位数
*/
int length = 4;
/**
* 验证码有效时间 60s
*/
int expireIn = 60;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
Random random = new Random();
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
g.setFont(new Font("Times New Roman", Font.ITALIC, 20));
g.setColor(getRandColor(160, 200));
for (int i = 0; i < 155; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x, y, x + xl, y + yl);
}
StringBuilder sRand = new StringBuilder();
for (int i = 0; i < length; i++) {
String rand = String.valueOf(random.nextInt(10));
sRand.append(rand);
g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
g.drawString(rand, 13 * i + 6, 16);
}
g.dispose();
return new ImageCode(image, sRand.toString(), expireIn);
}
/**
* 获取随机颜色
*
* @param fc
* @param bc
* @return
*/
public static Color getRandColor(int fc, int bc) {
Random random = new Random();
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);
}
}
成功!
但是感觉有点问题,因为存储验证码到session的key是同一个,这就有可能导致自己的验证码被别人刷失效,这个问题后面再研究