验证码的作用
验证码的作用:可以有效防止其他人对某一个特定的注册用户用特定的程序暴力破解方式进行不断的登录尝试
我们其实很经常看到,登录一些网站其实是需要验证码的,比如牛客,QQ等。使用验证码是现在很多网站通行的一种方式,这个问题是由计算机生成并且评判的,但是必须只有人类才能解答,因为计算机无法解答验证码的问题,所以回答出问题的用户就可以被认为是人类。
验证码一般用来防止批量注册。
案例要求
验证码本质:后端程序随机验证码
图片的创建:
---java api手动创建图片
---JavaScript 前端创建图片
验证码的刷新
---添加JavaScript的点击事件,重新请求验证码图片
前端页面准备
因为涉及到jQuery,所以需要在resources/static创建目录,存放jQuery库
准备login.html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
<!--引入jQuery -->
<script type="text/javascript" src="/js/jquery-1.8.3.min.js"></script>
</head>
<body>
<h2>用户登录</h2>
<form action="/login" method="post">
用户名:<input type="text" name="username"><br><br>
密码 :<input type="password" name="password"><br><br>
验证码:<input id="identify-input" type="text" name="identifyCode">
<img id="identify-img" src="/identifyImage"><br><br>
<input type="submit" value="登录">
</form>
<!--绑定点击事件 -->
<script>
$("#identify-img").on('click',function (){
// 点击验证码那个图片的时候,我们输入的验证码那个框就会清空
$('#identify-input').val('')
//而且我们点击验证码的时候,希望它可以改变验证码内容,其实是通过发送新请求来改变验证码内容
$('#identify-img').attr('src','/identifyImage?'+Math.random())
})
</script>
</body>
</html>
随机验证码工具类
public class IdentifyCodeUtils {
//设置图片宽
private int width = 95;
//设置图片高度
private int height = 25;
//设置干扰线数量
private int lineSize = 40;
//随机产生数字和字母组合的字符串
private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Random random = new Random();
/**
* 获得字体
*/
private Font getFont() {
return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
}
/**
* 获得颜色
*/
private Color getRandColor(int fc, int bc) {
if (fc > 255) {
fc = 255;
}
if (bc > 255) {
bc = 255;
}
int r = fc + random.nextInt(bc - fc - 16);
int g = fc + random.nextInt(bc - fc - 14);
int b = fc + random.nextInt(bc - fc - 18);
return new Color(r, g, b);
}
/**
* 获取验证码
*
* @return
*/
public String getIdentifyCode() {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < 4; i++) {
char c = randString.charAt(random.nextInt(randString.length()));
buffer.append(c);
}
return buffer.toString();
}
/**
* 生成随机图片
*
* @param identifyCode
* @return
*/
public BufferedImage getIdentifyImage(String identifyCode) {
//BufferedImage类是具有缓冲区的Image类,Image类是用来描述图像信息的类
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
//产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
Graphics graphics = image.getGraphics();
//图片大小
graphics.fillRect(0, 0, width, height);
//字体大小
graphics.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));
//字体颜色
graphics.setColor(getRandColor(110, 133));
//绘制干扰线
for (int i = 0; i <= lineSize; i++) {
drawLine(graphics);
}
//绘制随机字符
drawString(graphics, identifyCode);
graphics.dispose();
return image;
}
/**
* 绘制字符串
*/
private void drawString(Graphics g, String identifyCode) {
for (int i = 0; i < identifyCode.length(); i++) {
g.setFont(getFont());
g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
.nextInt(121)));
g.translate(random.nextInt(3), random.nextInt(3));
g.drawString(String.valueOf(identifyCode.charAt(i)), 13 * i + 20, 18);
}
}
/**
* 响应验证码图片
*
* @param identifyImg
* @param response
*/
public void responseIdentifyImg(BufferedImage identifyImg, HttpServletResponse response) {
//设置响应类型,告诉浏览器输出的内容是图片
response.setContentType("image/jpeg");
//设置响应头信息,告诉浏览器不用缓冲此内容
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expire", 0);
try {
//把内存中的图片通过流动形式输出到客户端
ImageIO.write(identifyImg, "JPEG", response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 绘制干扰线
*/
private void drawLine(Graphics graphics) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(13);
int yl = random.nextInt(15);
graphics.drawLine(x, y, x + xl, y + yl);
}
}
后端控制器
@Controller
public class UserController {
@RequestMapping("/loginShow")
public String loginShow(){
return "login.html";
}
@PostMapping("/login")
public String login(String username,String password,String identifyCode,HttpSession session){
System.out.println("用户名:"+username);
System.out.println("密码:"+password);
System.out.println("验证码:"+identifyCode);
//从session中取出验证码
String sessionCode = (String)session.getAttribute("identifyFyCode");
if (identifyCode.equalsIgnoreCase(sessionCode)){
System.out.println("验证码正确");
//进行登录判断的逻辑大家自己写,这里就不演示了
}else{
System.out.println("验证码错误");
//重定向到登录画面
return "redirect:/loginShow";
}
return "";
}
/**
* 给前端返回一个验证码图片
* @return
*/
@RequestMapping("/identifyImage")
public void identifyImage(HttpServletResponse response, HttpSession session){
//创建随机验证码
IdentifyCodeUtils utils = new IdentifyCodeUtils();
String identifyCode = utils.getIdentifyCode();
//session存入验证码
session.setAttribute("identifyCode", identifyCode);
//根据验证码创建图片
BufferedImage identifyImage = utils.getIdentifyImage(identifyCode);
//回传给前端
utils.responseIdentifyImg(identifyImage,response);
}
}
测试
当我们点击验证码这个图片的时候,它就会生成新验证码
并且如果我们在输入框中如果有写验证码的话,当我们点击验证码图片,它就会把输入框内容清空(大家自己测试)