当前位置: 首页 > ds >正文

[Java实战]Spring Security 添加验证码(二十三)

[Java实战]Spring Security 添加验证码(二十三)

在现代的 Web 应用中,验证码是防止恶意攻击(如暴力破解、自动注册等)的重要手段之一。Spring Security 是一个功能强大的安全框架,提供了用户认证、授权等功能。本文将详细介绍如何在 Spring Security 中添加验证码功能,从而进一步增强应用的安全性。

一. 环境准备

  • openJDK 17+:Spring Boot 3 要求 Java 17 及以上。
  • Spring Boot 3.4.5:使用最新稳定版。
  • 构建工具:Maven 或 Gradle(本文以 Maven 为例)。

二、验证码的作用

验证码(CAPTCHA,Completely Automated Public Turing test to tell Computers and Humans Apart)是一种区分用户是人类还是机器人的测试。常见的验证码类型包括:

  • 图片验证码:用户需要识别并输入图片中的字符。
  • 短信验证码:用户需要输入发送到手机的验证码。
  • 邮箱验证码:用户需要输入发送到邮箱的验证码。

验证码的主要作用是:

  • 防止暴力破解:限制非法登录尝试。
  • 防止自动注册:限制恶意用户批量注册账号。
  • 防止垃圾评论:限制自动发布垃圾评论。

三、Spring Security 添加验证码

1. 添加依赖

在 Spring Boot 项目中,添加验证码功能需要一些额外的依赖。首先,确保你的项目中已经添加了 Spring Security 和 Spring Web 的依赖。

<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot Starter Security --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- Thymeleaf --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- 图片验证码库 --><dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version></dependency><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>6.0.0</version><scope>provided</scope></dependency>
</dependencies>

2. 配置验证码生成器

使用 Kaptcha 库生成图片验证码。首先,配置 Kaptcha 的 Bean。

@Configuration
public class KaptchaConfig {@Beanpublic Producer kaptchaProducer() {Properties properties = new Properties();properties.put("kaptcha.border", "no");properties.put("kaptcha.textproducer.font.color", "black");properties.put("kaptcha.textproducer.char.space", "5");properties.put("kaptcha.image.width", "125");properties.put("kaptcha.image.height", "45");properties.put("kaptcha.textproducer.char.len", "5");properties.put("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");DefaultKaptcha kaptcha = new DefaultKaptcha();kaptcha.setConfig(new Config(properties));return kaptcha;}
}

3. 创建验证码控制器

创建一个控制器,用于生成和显示验证码图片。

@RestController
public class KaptchaController {@Autowiredprivate Producer kaptchaProducer;@GetMapping("/captcha")public void getKaptcha(HttpServletResponse response, HttpSession session) throws IOException, IOException {response.setDateHeader("Expires", 0);response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");response.addHeader("Cache-Control", "post-check=0, pre-check=0");response.setHeader("Pragma", "no-cache");response.setContentType("image/jpeg");String capText = kaptchaProducer.createText();session.setAttribute("captcha", capText);BufferedImage bi = kaptchaProducer.createImage(capText);ServletOutputStream out = response.getOutputStream();ImageIO.write(bi, "jpg", out);try {out.flush();} finally {out.close();}}
}

4. 修改登录页面

在登录页面login.html中添加验证码输入框和验证码图片。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Login</title>
</head>
<body>
<form th:action="@{/login}" method="post"><div><label>Username: <input type="text" name="username"></label></div><div><label>Password: <input type="password" name="password"></label></div><div><label>Captcha: <input type="text" name="captcha"></label></div><div><img th:src="@{/captcha}" alt="captcha" onclick="this.src='/captcha?'+new Date()" style="cursor:pointer;"></div><div><input type="submit" value="Sign In"></div>
</form>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

5. 修改 SecurityConfig

SecurityConfig 中添加验证码校验逻辑。

@Configuration
@EnableWebSecurity
public class SecurityConfig {@Autowiredprivate CustomUserDetailsService userDetailsService;@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.csrf(csrf -> csrf.disable()).authorizeHttpRequests(authorize -> authorize.requestMatchers("/admin/**").hasRole("ADMIN").requestMatchers("/user/**").hasRole("USER").requestMatchers("/", "/home", "/register", "/captcha").permitAll().anyRequest().authenticated()).formLogin(form -> form.loginPage("/login").permitAll().defaultSuccessUrl("/home", true)).logout(logout -> logout.permitAll()).addFilterBefore(new CaptchaFilter(), UsernamePasswordAuthenticationFilter.class);return http.build();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {return config.getAuthenticationManager();}

6. 创建验证码过滤器

创建一个自定义过滤器,用于校验验证码。


public class CaptchaFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {// 仅拦截登录请求(POST 方法)if ("POST".equalsIgnoreCase(request.getMethod())&& "/login".equals(request.getRequestURI())) {// 从前端获取验证码参数(根据方案一或二调整名称)String inputCaptcha = request.getParameter("captcha");String sessionCaptcha = (String) request.getSession().getAttribute("captcha");// 校验逻辑if (inputCaptcha == null || inputCaptcha.isEmpty()|| !inputCaptcha.equalsIgnoreCase(sessionCaptcha)) {// 清除旧验证码并记录错误request.getSession().removeAttribute("captcha");request.getSession().setAttribute("captchaError", "验证码错误");response.sendRedirect("/login?error");return;}// 验证通过后清除验证码(避免重复使用)request.getSession().removeAttribute("captcha");}filterChain.doFilter(request, response);}
}

四、高级用法

1. 短信验证码

除了图片验证码,你还可以使用短信验证码。以下是一个简单的实现示例:

添加依赖
<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>4.5.0</version>
</dependency>
<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-dysmsapi</artifactId><version>1.1.0</version>
</dependency>
配置短信服务
@Service
public class SmsService {public void sendSms(String phone, String code) {DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "your-access-key-id", "your-access-key-secret");IAcsClient client = new DefaultAcsClient(profile);CommonRequest request = new CommonRequest();request.setMethod(MethodType.POST);request.setDomain("dysmsapi.aliyuncs.com");request.setVersion("2017-05-25");request.setAction("SendSms");request.putQueryParameter("RegionId", "cn-hangzhou");request.putQueryParameter("PhoneNumbers", phone);request.putQueryParameter("SignName", "your-sign-name");request.putQueryParameter("TemplateCode", "your-template-code");request.putQueryParameter("TemplateParam", "{\"code\":\"" + code + "\"}");try {CommonResponse response = client.getCommonResponse(request);System.out.println(response.getData());} catch (ServerException e) {e.printStackTrace();} catch (ClientException e) {e.printStackTrace();}}
}
修改登录页面

在登录页面中添加短信验证码输入框。

<div><label>SMS Captcha: <input type="text" name="smsCaptcha"></label></div>
修改验证码过滤器

在验证码过滤器中添加短信验证码校验逻辑。

public class CaptchaFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {if ("/login".equals(request.getRequestURI())) {String captcha = request.getParameter("captcha");String smsCaptcha = request.getParameter("smsCaptcha");String sessionCaptcha = (String) request.getSession().getAttribute("captcha");String sessionSmsCaptcha = (String) request.getSession().getAttribute("smsCaptcha");if (captcha == null || !captcha.equalsIgnoreCase(sessionCaptcha)) {request.getSession().setAttribute("captchaError", "Invalid captcha");response.sendRedirect("/login");return;}if (smsCaptcha == null || !smsCaptcha.equalsIgnoreCase(sessionSmsCaptcha)) {request.getSession().setAttribute("smsCaptchaError", "Invalid SMS captcha");response.sendRedirect("/login");return;}}filterChain.doFilter(request, response);}
}

五、常见问题与解决方案

1. 验证码不显示

原因:Kaptcha 配置不正确,或服务器未正确返回图片。

解决方案

  • 检查 Kaptcha 的配置是否正确。
  • 确保 KaptchaController 中的 getKaptcha 方法返回正确的图片。

2. 验证码校验失败

原因:验证码输入错误,或验证码已过期。

解决方案

  • 确保用户输入的验证码正确。
  • 检查验证码的有效期是否过期。

3. 短信验证码发送失败

原因:短信服务配置不正确,或网络问题。

解决方案

  • 检查短信服务的配置是否正确。
  • 确保网络连接正常。

六、总结

本文详细介绍了如何在 Spring Security 中添加验证码功能,包括图片验证码和短信验证码。通过合理使用验证码,可以显著增强应用的安全性。希望本文能帮助你更好地理解和使用 Spring Security 添加验证码。

如果你在使用过程中遇到任何问题,欢迎在评论区留言交流。感谢你的阅读,希望这篇文章对你有所帮助!

http://www.xdnf.cn/news/6277.html

相关文章:

  • android实现USB通讯
  • 基于 Kubernetes 部署容器平台kubesphere
  • CCF第七届AIOps国际挑战赛季军分享(RAG)
  • YOLO v2:目标检测领域的全面性进化
  • 记录 QT 在liunx 下 QFileDialog 类调用问题 ()Linux下QFileDialog没反应)
  • AI日报 · 2025年5月14日|Android 生态大型更新与多端 Gemini 集成
  • UPS是什么?UPS 不间断电源有哪些适配的升压芯片?
  • zabbix7.2最新版本 nginx自定义监控(三) 设置触发器
  • MySQL之基础索引
  • postman 用法 LTS
  • 互联网大厂Java求职面试:AI内容生成平台下的高并发架构设计与性能优化
  • CycleISP: Real Image Restoration via Improved Data Synthesis通过改进数据合成实现真实图像恢复
  • Linux grep -r 查找依赖包是否存在依赖类 Class
  • 【Pycharm】pycharm修改注释文字的颜色
  • HDD 安全擦除:何时以及如何在 Windows PC 上安全擦除硬盘
  • 【SSL证书系列】客户端如何检查中间CA签名是否由根CA签发
  • 应用示例1:交通灯
  • 怎么快速换电脑浏览器的ip:方法与注意事项
  • Java零基础学习Day13——面向对象进阶
  • ClickHouse详解
  • Android学习总结之Glide自定义三级缓存(实战篇)
  • Linux相关概念和易错知识点(39)(URL、HTTP)
  • PlantSimulation 隐藏 Frame节点(Structure)的操作方法
  • 怎么实现Redis的高可用?
  • k8s 中使用 Service 访问时NetworkPolicy不生效问题排查
  • 快消零售AI转型:R²AIN SUITE如何破解效率困局
  • 电脑内存智能监控清理,优化性能的实用软件
  • linux - 权限的概念
  • BMS工具箱用来执行贝叶斯模型平均(BMA)计算模块
  • 最大熵逆强化学习