在打开认证验证码功能时遇到了一个这样的问题:
验证码已失效,请刷新后重试
相关后端代码:
// 验证码发送
public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 定义图形验证码的宽、高、验证码字符数、干扰线的条数
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100, 30, 4, 20);
// 获取验证码中的文本
String code = lineCaptcha.getCode();
// 将验证码存储在会话中,用于后续验证
request.getSession().setAttribute("captcha", code);
// 设置响应的内容类型为图片
response.setContentType("image/png");
// 获取输出流
ServletOutputStream outputStream = response.getOutputStream();
// 将验证码写出到输出流
lineCaptcha.write(outputStream);
// 关闭输出流
outputStream.close();
}
// 登录
public R<LoginUserVo> login(String username, String password, String captcha, HttpServletRequest request) {
try{
// 0. 校验验证码
String sessionCaptcha = (String) request.getSession().getAttribute("captcha");
if (sessionCaptcha == null) {
throw new BusinessException(400, "验证码已失效,请刷新后重试");
}
if (!sessionCaptcha.equalsIgnoreCase(captcha)) {
throw new BusinessException(400, "验证码错误");
}
// 验证码一次性使用
request.getSession().removeAttribute("captcha");
...
}
}原因分析:获取验证码后,调用login接口时没有携带上cookie。
为啥没有携带嘞?
因为部署时前端地址为http://lvmaoya.cn:8520,api地址为https://api.lvmaoya.cn。发生跨域,现在所有现代浏览器(Chrome、Safari、Edge):跨域 cookie 必须 SameSite=None,否则浏览器会自动阻止。
解决方案:
- Nginx 设置 Set-Cookie:
proxy_cookie_path / "/; SameSite=None; Secure";
// 检验可行2. springBoot + springScurity应用配置:应该在这里配置sameSiteCookies相关属性,没有试过。
public CorsFilter corsFilter() {
// 创建CorsConfiguration对象
CorsConfiguration config = new CorsConfiguration();
// 允许所有来源(根据需求可以设置为具体的域名)
config.setAllowedOrigins(Arrays.asList(
"https://lvmaoya.cn",
"http://localhost:3001",
"http://lvmaoya.cn:8520"
));
// 允许所有请求头
config.addAllowedHeader("*");
// 允许所有HTTP方法(GET、POST、PUT、DELETE等)
config.addAllowedMethod("*");
// 允许携带凭证(如Cookie)
config.setAllowCredentials(true);
// 创建UrlBasedCorsConfigurationSource对象
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 对所有路径应用CORS配置
source.registerCorsConfiguration("/**", config);
// 返回CorsFilter
return new CorsFilter(source);
}⚠️ 注意:
- 前端在请求时 axios.defaults.withCredentials = true; 否则 cookie 依然带不上。
- SameSite=None 时浏览器要求同时:Secure(HTTPS 才允许)
回顾一下这整个验证流程:
① 前端请求 /captcha
↓
② 后端创建 Session → 保存验证码到 Session
↓
③ 响应返回时发送 Set-Cookie(JSESSIONID)
↓
④ 浏览器保存 Cookie
↓
⑤ 前端请求 /login 带上同样的 Cookie
↓
⑥ 后端通过 JSESSIONID 找到同一个 Session
↓
⑦ 后端取出 session["captcha"] 进行验证