客户端向服务端请求验证码

src="服务端验证码servlet"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<img 
id="captcha"
onclick="refreshCaptcha()"
class="codeImage"
alt="验证码"
src="${ctx}/checkCode"
title="点击更换验证码"
/>

<script>
function refreshCaptcha() {
$("#captcha").attr("src", "/checkCode" + "?nocache=" + new Date().getTime());
}
<script>

  接收客户端验证码请求,调用CaptchaImageUtil生成验证码图片,并将其返回给客户端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package servlet;

import utils.CaptchaImageUtil;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;

/**
* 接收客户端验证码请求,调用CaptchaImageUtil生成验证码图片,并将其返回给客户端。
*
* @author imp2002
* @date 2021-04-09 17:23
*/

@WebServlet(name = "CaptchaServlet", value = "/checkCode")
public class CaptchaServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置浏览器不缓存
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "No-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");

BufferedImage image = CaptchaImageUtil.getPicture(80, 35, request);
ImageIO.write(image, "JPEG", response.getOutputStream());
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}

服务端生成验证码

  CaptchaImageUtil随机生成长度为4的字符串作为验证码,使用awt绘制包含该字符串的图片,为了增加验证码的安全级别防止ORC,在绘制图片时绘制干扰线。同时将该字符串存Session。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package utils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.Random;

/**
* 生成验证码图像
*
* @author imp2002
* @date 2021-04-09 17:38
*/
public class CaptchaImageUtil {

/**
* 生成随机颜色
*
* @param s
* @param e
* @return java.awt.Color
*/
private static Color getRandColor(int s, int e) {
Random random = new Random();
if (s > 255)
s = 255;
if (e > 255)
e = 255;
int r, g, b;
r = s + random.nextInt(e - s); // 随机生成RGB颜色中的r值
g = s + random.nextInt(e - s); // 随机生成RGB颜色中的g值
b = s + random.nextInt(e - s); // 随机生成RGB颜色中的b值
return new Color(r, g, b);
}

/**
* @param width,height 验证码的宽度和高度
* @return BufferedImage image对象
* @request 传入需要获取验证码图片的会话请求,将验证码四位验证码放入 session 中
*/
public static BufferedImage getPicture(int width, int height, HttpServletRequest request) {
// 随机字符集合中去除掉0和o,O,1和l等不易区分的图像
String CHECK_CODES = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
Graphics2D g2d = (Graphics2D) g;

Random random = new Random();
Font font = new Font("幼圆", Font.BOLD, 25);
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
g.setFont(font);
g.setColor(getRandColor(180, 200));

// 绘制50条颜色和位置全部为随机产生的线条,该线条为2f
for (int i = 0; i < 50; i++) {
int x = random.nextInt(width - 1);
int y = random.nextInt(height - 1);
int x1 = random.nextInt(6) + 1;
int y1 = random.nextInt(12) + 1;
BasicStroke bs = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
Line2D line = new Line2D.Double(x, y, x + x1, y + y1);
g2d.setStroke(bs);
g2d.draw(line);
}

// 用来保存验证码字符串文本内容
StringBuilder sb = new StringBuilder();

for (int i = 0; i < 4; ++i) {
char charAt = CHECK_CODES.charAt(random.nextInt(CHECK_CODES.length()));
String sTemp = String.valueOf(charAt);
sb.append(sTemp);

Color color = new Color(20 + random.nextInt(110), 20 + random.nextInt(110), random.nextInt(110));
g.setColor(color);
// 将生成的随机数进行随机缩放并旋转制定角度 PS.建议不要对文字进行缩放与旋转,因为这样图片可能不正常显示

// 将文字旋转制定角度
Graphics2D g2d_word = (Graphics2D) g;
AffineTransform trans = new AffineTransform();
trans.rotate((45) * 3.14 / 180, 15 * i + 8, 7);

// 缩放文字
float scaleSize = random.nextFloat() + 0.8f;
if (scaleSize > 1f)
scaleSize = 1f;
trans.scale(scaleSize, scaleSize);
g2d_word.setTransform(trans);
g.drawString(sTemp, 15 * i + 18, 14);
}

HttpSession session = request.getSession(true);
System.out.println("验证码绘制:" + sb);
// 存入session
session.setAttribute("captcha", sb.toString());
g.dispose();

return image;
}
}

验证码验证

  客户端收到验证码图片后,输入验证码随账号密码一起提交至服务端,服务端将客户端输入的验证码与Session中保存的验证码进行比对,返回结果给客户端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package servlet;

import dao.UserDao;
import entity.User;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;

/**
* @author imp2002
* @date 2021-04-09 17:44
*/

@WebServlet(name = "LoginServlet", value = "/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
String captcha = request.getParameter("captcha");

UserDao userDao = new UserDao();
User user = null;

try {
user = userDao.login(username, password);
} catch (SQLException e) {
e.printStackTrace();
}
HttpSession session = request.getSession();
System.out.println("服务端生成的验证码" + session.getAttribute("captcha"));
System.out.println("输入的验证码" + captcha);

if (!captcha.equalsIgnoreCase((String) session.getAttribute("captcha"))) {
request.setAttribute("loginInfo", "201");

} else if (user != null) {
// 不直接跳转到后台,返回信息到登录页面,登录页面凭此信息再跳转到后台
// response.sendRedirect("device/list");
request.setAttribute("loginInfo", "200");
} else {
request.setAttribute("loginInfo", "403");
}
request.getRequestDispatcher("/login.jsp").forward(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}