Spring Boot 集成验证码
方法 1
在 pom.xml 文件中引入依赖:
<!-- https://mvnrepository.com/artifact/com.github.axet/kaptcha -->
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<version>0.0.9</version>
</dependency>
在 config 包中新建验证码配置类:
import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
/**
* <p> 验证码配置
* @author mk
* @date 2020.01.04
*
*/
@Configuration
public class KaptchaConfig {
@Bean
public Producer producer() {
Properties properties = new Properties();
properties.put(Constants.KAPTCHA_BORDER, "no");
properties.put(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
properties.put(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "5");
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(new Config(properties));
return defaultKaptcha;
}
}
在 controller 包中新建控制器类:
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
/**
* <p> 登录控制器
* @author mk
* @date 2020.01.04
*
*/
@RestController
public class LoginController {
@Autowired
private Producer producer;
/**
* <p> 验证码
* <p> 参考:com.google.code.kaptcha.servlet.KaptchaServlet
* @param request
* @param response
* @throws IOException
*/
@GetMapping("captcha.jpg")
public void captcha(HttpServletRequest request, HttpServletResponse response) {
// 参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ
response.setHeader("Cache-Control", "no-store, no-cache"); // Set standard HTTP/1.1 no-cache headers
response.setContentType("image/jpeg"); // return a jpeg
String text = producer.createText(); // create the text for the image
BufferedImage image = producer.createImage(text); // create the image with the text
HttpSession session = request.getSession();
// store the text in the session
session.setAttribute(Constants.KAPTCHA_SESSION_CONFIG_KEY, text);
// store the date in the session so that it can be compared
// against to make sure someone hasn't taken too long to enter
// their captcha
session.setAttribute(Constants.KAPTCHA_SESSION_CONFIG_DATE, new Date());
ServletOutputStream out = null;
try {
out = response.getOutputStream();
ImageIO.write(image, "jpg", out); // write the data out
} catch (IOException e) {
session.removeAttribute(Constants.KAPTCHA_SESSION_CONFIG_KEY);
session.removeAttribute(Constants.KAPTCHA_SESSION_CONFIG_DATE);
e.printStackTrace();
} finally {
IOUtils.closeQuietly(out); // 关闭输出流
}
}
}
运行启动类,访问 http://localhost:8080/captcha.jpg
方法 2
使用 Hutool 工具包提供的图形验证码
引入 Hutool 工具包的依赖:
<hutool-all.version>5.0.7</hutool-all.version>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-all.version}</version>
</dependency>
图形验证码控制器类:
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
@RestController
public class CaptchaController {
@GetMapping("/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
String referer = request.getHeader("referer");
if ((referer != null) && (referer.equalsIgnoreCase("http://localhost:8080/login.html"))) { // 来自登录页面的请求
int width = 116;
int height = 36;
int codeCount = 4;
int lineCount = 10;
// 创建图形验证码
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(width, height, codeCount, lineCount);
ServletOutputStream out = null;
try {
// 将图形验证码写到响应输出流
out = response.getOutputStream();
// lineCaptcha.write(out);
ImageIO.write(lineCaptcha.getImage(), "JPEG", out);
out.flush();
// 保存验证码
String code = lineCaptcha.getCode();
session.setAttribute("code", code);
System.out.println(code);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(out);
}
} else { // 拒绝其他路径的请求
response.setStatus(HttpStatus.NOT_FOUND.value());
}
}
}
在图形验证码控制器类中,通过查询 Referer 请求头判断请求验证码的来源地址。
Referer 请求头包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。
参考:Referer
登录页面 src/main/resources/static/login.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form class="login-page" action="/login" method="post">
<div class="form">
<h3>账户登录</h3>
<input type="text" placeholder="用户名" name="username" required="required" />
<input type="password" placeholder="密码" name="password" required="required" />
<span style="display: inline">
<input type="text" name="captcha" placeholder="验证码" />
<img src="/captcha" style="width: 100px; height: 22px"/>
</span>
<button type="submit">登录</button>
</div>
</form>
</body>
</html>
图形验证码的效果:
通过 Referer 请求头限制非登录页面访问图形验证码的效果: