图形验证码整体流程大概是:
- 页面初始化的时候服务器生成一个验证码,然后将验证码保存到session中,再显示给html(客户端)
- 整合springsecurity校验,自定义一个filter,将该filter设置在UsernamePasswordAuthenticationFilter之前执行,这样就会在验证用户名密码之前就校验验证码
- 在我第三步我们自定义的filter里面校验html传来的验证码和第二步我们保存到session的验证码是否想要,如果相同那么就放行,验证成功
接下来我们看看每一步的代码具体怎么实现
- 页面初始化的时候服务器生成一个验证码,然后将验证码保存到session中,再显示给html(客户端)
首先我们得新建一个类ImageCode用来存放验证码信息
public class ImageCode { private BufferedImage image; private String code; private LocalDateTime expireTime;//过期时间 /** * * @param image * @param code * @param expireInt :该参数是过期时间秒数,如60 */ public ImageCode(BufferedImage image, String code, int expireInt) { this.image = image; this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireInt);//当前时间加上60秒 } }
然后生成一个验证码(ImageCode)对象
package org.spring.springcloud.config.springSecurity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; @RestController public class ImageCodeController { // private SessionStrategy sessionStrategy=new HttpSessionSessionStrategy(); @RequestMapping(value="/imageCode" ,method = RequestMethod.GET) public void imageCode(HttpServletRequest request , HttpServletResponse response,HttpSession session) throws IOException { //生成imageCode对象 ImageCode imageCode=createImageCode(); //将图形验证码存入到session中 request.getSession().setAttribute("imageCode",imageCode); // 将生成的图片写到接口的响应中 ImageIO.write(imageCode.getImage(),"JPEG",response.getOutputStream()); } private ImageCode createImageCode() { int width=80; int height=30; 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); } String code = ""; for (int i = 0; i < 4; i++) { String rand = String.valueOf(random.nextInt(10)); code += 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, code, 60); } /** * 生成随机背景条纹 * * @param fc * @param bc * @return */ private 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); } }
- 整合springsecurity校验,自定义一个filter,将该filter设置在UsernamePasswordAuthenticationFilter之前执行,这样就会在验证用户名密码之前就校验验证码
package org.spring.springcloud.config.springSecurity.filter;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@Component
public class ValidateCodefilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String uri= request.getRequestURI();
//如果为get请求并且请求uri为/login(也就是我们登录表单的form的action地址)
if( StringUtils.equalsIgnoreCase(request.getMethod(),"get") && StringUtils.containsIgnoreCase(request.getRequestURI(),"/login"))
{
logger.info("ValidateCodefilter执行了----" + "request.getRequestURI()=" + uri);
//这里需要验证前端传过来的验证码是否和session里面存的一致,并且要判断是否过期
logger.info(request.getSession().getAttribute("imageCode"));
validateCode(request);
}
filterChain.doFilter(request,response);
}
/**
* 验证用户输入的验证码和session中存的是否一致
* @param request
*/
private void validateCode(HttpServletRequest request) {
}
}
在securiryConfig文件中将该filter设置在UsernamePasswordAuthenticationFilter之前执行
http.addFilterBefore(validateCodefilter,UsernamePasswordAuthenticationFilter.class);
验证码功能到这里就完成了