即墨有做网站的吗深圳搜索引擎优化seo
目录
Spring Security 验证码登录完整实现(基于 Hutool)
验证码登录核心流程
一、前端页面说明
二、验证码生成 Controller 说明
三、验证码拦截器(CaptchaFilter)说明
四、拦截器注册及过滤器链配置
配置对应的拦截器进行拦截(只针对于登录)
注册方式说明
五、整体流程概述
Spring Security 验证码登录完整实现(基于 Hutool)
验证码登录核心流程
前端页面:提供用户名、密码和验证码输入框,验证码图片通过 img
标签加载后端接口。
后端生成验证码:
通过 Hutool
生成验证码图片,并存入 Session
或 Redis
以供后续校验。
用户提交登录请求:
后端先校验验证码是否正确。
验证码通过后:
Spring Security 继续验证用户名和密码,完成身份认证。
一、前端页面说明
前端页面添加验证码这一栏,注意图片的src是后端的接口(需要存在对应的接口与之对应)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录页面</title>
</head>
<body>
<form action="/login" method="post">用户名:<input type="text" name="username"><br>密码:<input type="password" name="password"><br>验证码:<input type="text" name="captcha"><img src="/common/captcha"><input name="_csrf" type="hidden" th:value="${_csrf.token}"><input type="submit" value="登录">
</form>
</body>
</html>
二、验证码生成 Controller 说明
使用Hutool工具包生成验证码图片
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.26</version>
</dependency>
定义一个Controller层接口生成验证码
@Controller // 标记为Spring MVC控制器
public class CaptchaController {@GetMapping("/common/captcha")public void generateCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {// 1. 生成验证码图片// 这里使用 Hutool 工具包提供的 CaptchaUtil 创建一个带扭曲干扰效果的验证码// 参数解释:// - 宽度:90像素// - 高度:30像素// - 验证码字符数:4个// - 干扰线数量:3条ICaptcha captcha = CaptchaUtil.createShearCaptcha(90, 30, new MyCodeGenerator(), 3);// 2. 将生成的验证码(文本)保存到 Session 中// 存入Session后,在后续登录校验中可以拿到正确的验证码进行比对request.getSession().setAttribute("captcha", captcha.getCode());// 3. 设置响应类型为 JPEG 图片response.setContentType("image/jpeg");// 4. 通过 IO 流将验证码图片写入到响应中// 这样前端页面中img标签请求该接口时,就能得到验证码图片captcha.write(response.getOutputStream());}
}
详细说明
控制器与接口映射
@Controller
:声明这是一个控制器类,通常用于返回视图页面。但这里虽然标注为@Controller
,方法内部通过直接输出流返回图片,所以实际上不做页面跳转。@GetMapping("/common/captcha")
:将 HTTP GET 请求/common/captcha
映射到该方法。前端访问此 URL 时,就会执行该方法生成验证码图片。
生成验证码
- 使用 Hutool 的
CaptchaUtil.createShearCaptcha(90, 30, new MyCodeGenerator(), 3)
: - ShearCaptcha:一种验证码实现,具有扭曲干扰效果,增加了识别难度。
参数解释:
- 90, 30:验证码图片宽度和高度。
- new MyCodeGenerator():自定义验证码字符生成器(例如只生成数字或特定字符)。
- 3:验证码图片中干扰线的数量。
保存验证码
request.getSession().setAttribute("captcha", captcha.getCode());
- 将生成的验证码字符串存入当前用户的 Session 中,方便后续在登录时进行比对验证。
输出验证码图片
- 设置响应头
Content-Type
为image/jpeg
表明响应内容为 JPEG 图片。 - 通过
captcha.write(response.getOutputStream());
将图片数据写入响应的输出流,前端可以直接显示该图片。
前端配合
前端页面通过 <img src="/common/captcha">
获取验证码图片,当用户点击图片时可以刷新验证码(通过改变 URL参数防止缓存)。
具体的详细API:
Hutool工具包生成验证码的接口-CSDN博客
三、验证码拦截器(CaptchaFilter)说明
允许该接口在未登录的情况下登录
.authorizeHttpRequests((authorizeHttpRequests)->{authorizeHttpRequests.requestMatchers("/toLogin","/common/captcha").permitAll() // 特殊情况,toLogin不需要登录就可以访问, 验证码不需要登录就可以访问.anyRequest().authenticated(); // 除了上述特殊情况之外,其他任何请求都需要认证之后才能访问})
完整代码:
@Configuration
public class SecurityConfig {/*** 密码加密:返回一个 BCryptPasswordEncoder 实例*/@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}// 定制 Spring Security 行为:自定义登录页和请求授权规则@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {return httpSecurity// 配置自定义登录页面,及登录提交的 URL.formLogin(formLogin -> {formLogin.loginProcessingUrl("/login") // 处理登录请求的接口.loginPage("/toLogin"); // 定制登录页面,未登录时跳转到该页面})// 配置访问控制规则.authorizeHttpRequests(authorizeHttpRequests -> {authorizeHttpRequests// 允许未登录访问的特殊接口:登录页面和验证码接口.requestMatchers("/toLogin", "/common/captcha").permitAll()// 其他所有请求都必须经过身份认证.anyRequest().authenticated();})// 构建 SecurityFilterChain 对象.build();}
}
详细说明
密码加密 Bean
- 定义
PasswordEncoder
Bean,返回BCryptPasswordEncoder
。 - BCrypt 算法可以对用户密码进行加密存储,同时在认证时进行密码匹配。
自定义登录页和登录处理
- 使用
formLogin()
配置登录: loginProcessingUrl("/login")
:指定前端提交用户名、密码及验证码时的目标 URL(登录表单提交地址)。loginPage("/toLogin")
:指定自定义登录页面,未登录时用户会跳转到该页面。
请求授权设置
requestMatchers("/toLogin", "/common/captcha").permitAll()
:设置/toLogin
和/common/captcha
这两个 URL 不需要登录即可访问。anyRequest().authenticated()
:除上述接口外,所有请求均需要用户先登录。
四、拦截器注册及过滤器链配置
配置对应的拦截器进行拦截(只针对于登录)
@Component
public class CaptchaFilter extends OncePerRequestFilter { // 继承OncePerRequestFilter,保证每个请求只执行一次@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 获取前端提交的验证码参数String code = request.getParameter("captcha");// 从 Session 中获取存储的正确验证码String captcha = (String) request.getSession().getAttribute("captcha");// 获取当前请求的路径String requestURI = request.getRequestURI();// 如果当前请求是登录请求,则需要校验验证码if (requestURI.equals("/login")) {// 如果没有填写验证码,或者验证码为空,则重定向到首页(或登录页,可根据实际业务调整)if (!StringUtils.hasText(code)) {response.sendRedirect("/");return;} else if (!code.equalsIgnoreCase(captcha)) {// 验证码不匹配时,同样重定向到首页response.sendRedirect("/");return;}// 如果验证码校验通过,则继续执行过滤链(后续会执行用户名密码认证等流程)filterChain.doFilter(request, response);} else {// 非登录请求直接放行filterChain.doFilter(request, response);}}
}
详细说明
继承 OncePerRequestFilter
OncePerRequestFilter
是 Spring 提供的一个过滤器基类,保证每个请求仅执行一次过滤操作。
验证码获取与比对
- 从请求参数中获取用户输入的验证码:
request.getParameter("captcha")
。 - 从 Session 中获取之前生成并保存的正确验证码:
request.getSession().getAttribute("captcha")
。 - 判断当前请求是否为
/login
(即提交登录表单时才需要验证验证码)。
验证码校验逻辑
- 如果验证码参数为空,调用
response.sendRedirect("/")
将请求重定向到首页(或可以根据需要重定向到登录页,提示用户重新输入验证码)。 - 如果验证码不匹配(忽略大小写),同样进行重定向。
- 如果验证码匹配,则调用
filterChain.doFilter(request, response)
放行,继续后续的过滤器链(包括用户名和密码认证)。
易错点:
记住登录请求并不是Controller层的登录请求而是表单提交时的action部分!!!例如在本例中是/login因为前端表单提交请求的路径是/login,而不是Controller层登录页面的映射路径:/toLogin
注册方式说明
在 SecurityConfig
中,我们需要在 Spring Security 内置的用户名密码认证过滤器之前添加我们自定义的验证码过滤器。注册方式如下:
// 注入自定义的验证码过滤器
@Resource
private CaptchaFilter captchaFilter;// 在Security配置中,使用addFilterBefore方法添加过滤器
httpSecurity// ...其他配置....addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
详细说明
过滤器的作用顺序
- 通过
addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
指定在 Spring Security 内置的UsernamePasswordAuthenticationFilter
之前先执行验证码校验。 - 这样一来,在用户提交登录请求时,系统会先验证验证码,如果验证码不正确则不会执行后续的用户名和密码校验,提高安全性。
拦截器注册成 Bean
@Component
注解将CaptchaFilter
注册为 Spring Bean。- 在
SecurityConfig
中通过@Resource
或@Autowired
注入该 Bean,从而在配置 SecurityFilterChain 时使用。
五、整体流程概述
验证码生成与前端显示
- 前端页面通过
<img src="/common/captcha">
请求验证码图片。 CaptchaController
生成验证码(这里使用带扭曲干扰的验证码),并将验证码字符串存入 Session,再将验证码图片通过 IO 流输出给前端。
请求访问控制
- Spring Security 配置中允许
/toLogin
(登录页面)和/common/captcha
(验证码图片接口)未登录访问。 - 其他请求都需要经过认证后才能访问。
登录请求及验证码校验
- 当用户提交登录表单(提交至
/login
)时,自定义的CaptchaFilter
会首先介入: - 从请求中获取用户输入的验证码,并从 Session 中获取正确验证码。
- 对比后若不匹配则直接重定向(例如重定向到首页),阻止后续登录认证流程。
- 若验证码校验通过,则继续执行后续的过滤器,进行用户名和密码认证。
过滤器链执行顺序
通过 addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
保证验证码校验在用户名密码认证之前执行。