Spring Security集成手机验证码登录实战指南
1. 项目概述在当今移动互联网时代手机验证码登录已成为各类应用的标准配置。作为一名长期使用Spring Security的开发者我发现很多团队在集成手机验证码登录时都会遇到各种坑——要么是验证流程设计不合理要么是与Spring Security原有体系融合不彻底。今天我就来分享一个经过多个生产项目验证的解决方案让你在5分钟内快速实现这一功能。这个方案的核心在于理解Spring Security的认证流程扩展点。不同于传统的用户名密码认证手机验证码登录需要自定义三个关键组件验证码生成与校验过滤器Filter、验证码认证令牌Token以及对应的认证提供者Provider。下面我会详细拆解每个环节的实现要点。2. 核心组件设计与实现2.1 验证码过滤器设计首先需要创建一个继承自OncePerRequestFilter的验证码过滤器。这个过滤器需要完成以下工作public class SmsCodeFilter extends OncePerRequestFilter { private static final String SMS_LOGIN_URL /login/mobile; Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (SMS_LOGIN_URL.equals(request.getRequestURI()) POST.equalsIgnoreCase(request.getMethod())) { try { validateCode(request); } catch (AuthenticationException e) { unsuccessfulAuthentication(request, response, e); return; } } filterChain.doFilter(request, response); } private void validateCode(HttpServletRequest request) { String mobile request.getParameter(mobile); String code request.getParameter(code); // 实际项目中这里应该调用验证码服务校验 if (!123456.equals(code)) { // 示例代码生产环境需要替换 throw new BadCredentialsException(验证码错误); } } private void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException { SecurityContextHolder.clearContext(); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, failed.getMessage()); } }关键点过滤器应该只拦截特定的验证码登录URL避免影响其他认证流程。验证失败时需要清除SecurityContext并返回401状态码。2.2 认证令牌与认证提供者接下来需要创建自定义的认证令牌和提供者public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken { private final Object principal; // 这里存储手机号 private Object credentials; // 这里存储验证码 public SmsCodeAuthenticationToken(Object principal, Object credentials) { super(null); this.principal principal; this.credentials credentials; setAuthenticated(false); } // 实现父类抽象方法 Override public Object getCredentials() { return this.credentials; } Override public Object getPrincipal() { return this.principal; } } Service public class SmsCodeAuthenticationProvider implements AuthenticationProvider { Autowired private UserDetailsService userDetailsService; Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { SmsCodeAuthenticationToken authenticationToken (SmsCodeAuthenticationToken) authentication; String mobile (String) authenticationToken.getPrincipal(); UserDetails user userDetailsService.loadUserByUsername(mobile); if (user null) { throw new UsernameNotFoundException(手机号未注册); } SmsCodeAuthenticationToken result new SmsCodeAuthenticationToken( user, null, user.getAuthorities()); result.setDetails(authenticationToken.getDetails()); return result; } Override public boolean supports(Class? authentication) { return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication); } }注意认证提供者中我们只验证用户是否存在因为验证码已经在过滤器中校验过了。这是职责分离的重要设计。3. Spring Security配置集成3.1 安全配置类将上述组件集成到Spring Security配置中Configuration EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { Autowired private SmsCodeAuthenticationProvider smsCodeAuthenticationProvider; Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(smsCodeFilter(), UsernamePasswordAuthenticationFilter.class) .authorizeRequests() .antMatchers(/code/sms).permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage(/login) .loginProcessingUrl(/login/form) .defaultSuccessUrl(/) .and() .logout() .logoutUrl(/logout) .logoutSuccessUrl(/login); } Bean public SmsCodeFilter smsCodeFilter() { return new SmsCodeFilter(); } Override protected void configure(AuthenticationManagerBuilder auth) { auth.authenticationProvider(smsCodeAuthenticationProvider); } }3.2 验证码发送接口虽然不属于Spring Security核心流程但验证码发送是完整功能的一部分RestController public class SmsCodeController { GetMapping(/code/sms) public Result sendSmsCode(RequestParam String mobile) { // 实际项目中这里应该调用短信服务发送验证码 String code generateRandomCode(); // 将验证码存入缓存设置5分钟过期 redisTemplate.opsForValue().set(sms_code: mobile, code, 5, TimeUnit.MINUTES); return Result.success(验证码已发送); } private String generateRandomCode() { return String.valueOf(new Random().nextInt(899999) 100000); } }4. 前端对接与测试4.1 前端登录表单手机验证码登录需要特定的表单form action/login/mobile methodpost input typetext namemobile placeholder手机号 input typetext namecode placeholder验证码 button typebutton onclicksendCode()获取验证码/button button typesubmit登录/button /form script function sendCode() { const mobile document.querySelector(input[namemobile]).value; fetch(/code/sms?mobile mobile) .then(response response.json()) .then(data alert(data.message)); } /script4.2 测试要点测试时需要关注以下几个关键点验证码有效期验证5分钟后应该失效同一手机号验证码防重放攻击验证码错误次数限制与原有表单登录的兼容性5. 生产环境注意事项在实际项目中还需要考虑以下问题验证码安全验证码长度建议6位包含数字即可设置合理的发送频率限制如60秒内只能发送一次同一IP/设备发送次数限制性能优化验证码校验使用Redis等内存数据库考虑使用本地缓存减少Redis访问异常处理短信服务不可用时的降级方案验证码输入错误时的友好提示日志记录记录验证码发送和验证日志关键操作需要审计日志我在实际项目中遇到过的一个典型问题当系统同时存在表单登录和验证码登录时如果用户先尝试表单登录失败再尝试验证码登录有时会出现认证状态混乱。解决方案是在过滤器中明确区分两种认证流程确保它们互不干扰。

相关新闻

EmuDeck终极指南:一键配置Steam Deck模拟器的完整解决方案

EmuDeck终极指南:一键配置Steam Deck模拟器的完整解决方案

EmuDeck终极指南:一键配置Steam Deck模拟器的完整解决方案 【免费下载链接】EmuDeck Emulator configurator for Steam Deck 项目地址: https://gitcode.com/gh_mirrors/em/EmuDeck EmuDeck是专为Steam Deck设计的模拟器自动配置工具,通过一键安装…

2026/7/19 12:36:29阅读更多 →
fp32-int4系列数据格式深入理解

fp32-int4系列数据格式深入理解

晚上在看一篇公众号的文章讲的是不同精度类型的数据,让我顿生了很多疑惑,以前做的大多是传统的深度学习模型,想要进行训练,更新梯度都是需要使用浮点类型才可以的,但是现在是大模型的时代,很多都是int类型的…

2026/7/19 12:36:29阅读更多 →
51单片机入门指南:从零到精通的10天学习路线

51单片机入门指南:从零到精通的10天学习路线

1. 为什么选择51单片机作为入门首选? 十年前我刚开始接触嵌入式开发时,面对琳琅满目的开发板完全无从下手。当时一位资深工程师递给我一块布满杜邦线孔的51开发板说:"把这个玩透了,其他单片机都是换汤不换药。"事实证明…

2026/7/19 12:34:29阅读更多 →
智能代码辅助工具:从核心原理到生产级应用实战指南

智能代码辅助工具:从核心原理到生产级应用实战指南

在实际技术项目中,我们经常需要处理文档生成、自动化脚本编写和代码辅助等任务。传统方式依赖手动编写或简单模板,效率有限且难以应对复杂需求。而借助智能代码辅助工具,可以显著提升开发效率和代码质量。本文将围绕一个实用的代码辅助工具展…

2026/7/19 19:26:13阅读更多 →
安卓性能优化实战:工具链与内存管理策略

安卓性能优化实战:工具链与内存管理策略

1. 安卓高性能编程的核心挑战 在移动应用开发领域,性能优化始终是开发者面临的关键挑战。不同于桌面或服务器环境,移动设备在计算能力、内存容量和电池续航等方面都存在显著限制。当用户抱怨应用"卡顿"、"耗电快"或"经常崩溃&q…

2026/7/19 19:26:13阅读更多 →
STM32毕设项目分享:水产运输水质监控系统设计(GPS、蓝牙)

STM32毕设项目分享:水产运输水质监控系统设计(GPS、蓝牙)

一、成品简介 1.实物成品 成品展示: 2.手机蓝牙APP 蓝牙APP界面: 二、项目简介 1.功能详解 水产运输水质监控系统设计(GPS、蓝牙) 水质参数采集:使用 PH 检测模块采集水体酸碱度;DS18B20 数字温度传感器采集车厢水体温度&#…

2026/7/19 19:26:13阅读更多 →
GPU与AI芯片技术对比及应用场景解析

GPU与AI芯片技术对比及应用场景解析

1. GPU与AI芯片的技术分野2023年NVIDIA市值突破万亿美元的关键节点,标志着GPU技术正式从图形渲染领域跃升为AI时代的算力基石。但当我们拆开一台搭载H100加速卡的AI服务器,会发现GPU与新兴的AI专用芯片(如TPU、NPU)在架构设计上存…

2026/7/19 19:26:13阅读更多 →
ComfyUI中文整合包部署指南:从零搭建AI绘画工作流

ComfyUI中文整合包部署指南:从零搭建AI绘画工作流

在 AI 绘画领域,Stable Diffusion 的 WebUI 虽然用户众多,但节点式工作流工具 ComfyUI 正凭借其可视化流程编排、显存占用低和可复用性强等特点,成为进阶用户和项目部署的首选。尤其对于显存有限的 30/40/50 系显卡用户,ComfyUI 能…

2026/7/19 19:26:13阅读更多 →
STM32井字棋无视觉方案:传感器检测与AI算法实战

STM32井字棋无视觉方案:传感器检测与AI算法实战

最近在准备电赛的同学应该都注意到了,2024年电赛E题"井字棋装置"确实是个热门题目。很多队伍都在纠结视觉方案的成本和复杂度问题,特别是对于大一新生来说,视觉识别系统的搭建确实存在不小的技术门槛。本文将分享一套完整的无视觉方…

2026/7/19 19:24:12阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/19 0:01:04阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/19 0:01:04阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/19 0:01:04阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/19 0:01:04阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/19 0:01:04阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/19 0:01:04阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/18 22:49:46阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/19 14:50:26阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/19 18:50:36阅读更多 →