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/10/18 13:41:46 阅读更多 →
SVGcode终极指南:3分钟将位图转为可无限放大的矢量图

SVGcode终极指南:3分钟将位图转为可无限放大的矢量图

SVGcode终极指南:3分钟将位图转为可无限放大的矢量图 【免费下载链接】SVGcode Convert color bitmap images to color SVG vector images. 项目地址: https://gitcode.com/gh_mirrors/sv/SVGcode 你是否曾为放大Logo时出现的模糊边缘而烦恼?或者…

2026/10/17 0:27:42 阅读更多 →
数据可观测性:现代数据架构的核心支柱

数据可观测性:现代数据架构的核心支柱

1. 数据可观测性的本质与价值 数据可观测性(Data Observability)正在成为现代数据架构的核心支柱。与传统的监控(Monitoring)不同,可观测性强调的是通过系统输出的外部特征来推断内部状态的能力。就像医生通过体温、血…

2026/10/18 20:33:01 阅读更多 →

最新新闻

模电前置知识

模电前置知识

一、基尔霍夫定律1、几个专有名词支路:电路中通过同一电流的分支结点:三条或三条以上支路的连接点称结点回路:由支路组成的闭合路径网孔:对平面电路,其内部不含任何支路的回路成网孔(网孔是回路&#xff0c…

2026/10/19 7:19:13 阅读更多 →
148.Agent-LangGraph状态的修改-归并函数operator和add_messages和MessagesState

148.Agent-LangGraph状态的修改-归并函数operator和add_messages和MessagesState

摘要:本文围绕 Python 的 operator 模块与函数式编程展开,先介绍高阶函数的概念与用法,再通过普通写法与函数式写法的对比,演示如何用 operator 中的 mul 等函数简化循环逻辑。随后引入 LangGraph 中 add_messages 与 MessagesSta…

2026/10/19 7:19:13 阅读更多 →
水利枢纽关键边界空间结构透视与人员禁入三维识别方案

水利枢纽关键边界空间结构透视与人员禁入三维识别方案

水利枢纽的安全管理,长期以来其实有一个很尴尬的痛点:视频监控装了无数路,围墙围栏修了一圈又一圈,但真正出事的时候,往往还是靠人盯着屏幕肉眼发现、事后翻录像大海捞针。传统的电子围栏误报率居高不下,小…

2026/10/19 7:19:13 阅读更多 →
激励与制衡:企业治理的双引擎与数字化落地实践

激励与制衡:企业治理的双引擎与数字化落地实践

1. 治理模型的双引擎:激励与制衡为什么必须被放在一起看1.1 从工程学视角切入管理问题我在长期做信息化系统设计的过程中,经常要面对一类问题:明明系统架构图画得漂漂亮亮,权限角色定义得清清楚楚,审批流嵌套了好几层&…

2026/10/19 7:19:13 阅读更多 →
2026网络安全七大趋势:AI对抗、零信任落地与数据安全工程化实践

2026网络安全七大趋势:AI对抗、零信任落地与数据安全工程化实践

2026年网络安全的风向,不会像技术发布会那样让人兴奋,但每一件都直接决定你是守得住还是被打穿。我从一线防护的角度,把未来一年最关键的七个变化拆开讲,每个趋势背后都有具体的攻击手法、防护思路和落地动作。这篇东西没有空话&a…

2026/10/19 7:19:13 阅读更多 →
【仿真】液冷板流道拓扑优化的思路与效果

【仿真】液冷板流道拓扑优化的思路与效果

摘要 液冷板流道设计本质上是压降与温差的权衡问题。本文从优化目标设定、拓扑优化算法选型、网格与求解器设置、多工况校核四个环节梳理液冷板流道拓扑优化的完整流程,并结合并联水道与串流道的对比说明优化收益的实际边界,可用于液冷板设计前期的方案…

2026/10/19 7:18:13 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →