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

cookie跨域共享踩的坑

微服务在进行登录验证时,通常有这样的需求:在登录时生成一个令牌,该令牌有一定的有效期。仅在该令牌有效的情况下可以访问登录成功后的界面。如没有令牌或令牌失效,则要将网页重定向到登录界面。这种业务需求需要配置cookie跨域共享。
本篇博客需要用到spring cloud gateway,如不知道如何配置,可以看一下这篇博客:spring cloud gateway配置。

一、配置文件

查询pom.xml里是否有以下依赖文件:

<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version> <!-- 或其他旧版本 --><scope>provided</scope>
</dependency>

如果有,看一下你的java版本是否大于等于9,从Java9开始要替换成以下配置文件:

    		<dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><scope>provided</scope></dependency>

添加配置文件后,在gateway微服务的application.yaml添加gateway配置:

spring:cloud:gateway:globalcors:cors-configurations:'[/**]':allowed-origins:- "http://localhost:8120"allowed-methods:- GET- POST- PUT- OPTIONSallowed-headers: "*"allow-credentials: trueexposedHeaders: "Set-Cookie"

二、前端代码

前端使用的是vue.js,网页把登录请求发送到gateway微服务,由gateway转发到相应微服务进行验证:

const response = await fetch('http://localhost:8110/api/login', {method: 'POST',headers: {'Content-Type': 'application/json',},credentials: 'include',body: JSON.stringify(this.formData)
});if (!response.ok) {throw new Error(`HTTP错误!状态码:${response.status}`);
}const result = await response.json();
alert('登录成功!');
// 跳转到签到页面
window.location.href = '/signIn';

登录成功后跳转到相关界面,该界面首先要进行令牌验证,相关代码如下:

async checkTokenValidity() {try {const res = await fetch('http://localhost:8110/api/validateToken', {method: 'POST',credentials: "include",headers: {'Content-Type': 'application/json'}});this.isTokenValid = res.ok;if (res.ok==false)window.location.href = '/login';} catch (err) {console.error('token验证失败:', err);this.redirectToLogin();}}

注:必须包含credentials: “include”

三、后端代码

后端需要生成jwt token,相关生成代码如下:

@Component
public class JwtConfig {private static final String SECRET_KEY = "nmPhPo7Ju/xgis3fXUyerWKVh4TrdFszIbuSnCiz4Vg="; //openssl rand -base64 32命令行生成private static final long EXPIRATION_TIME = 86400000; // 24小时(单位:毫秒)// 生成Tokenpublic String generateToken(String userId) {return Jwts.builder().setSubject(userId) // 用户唯一标识(如用户ID).setIssuedAt(new Date()) // 签发时间.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) // 过期时间.signWith(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()), SignatureAlgorithm.HS256) // 签名算法.compact();}// 验证Tokenpublic boolean validateToken(String token) {try {Jwts.parserBuilder().setSigningKey(SECRET_KEY.getBytes()).build().parseClaimsJws(token);return true;} catch (Exception e) {return false;}}}

登录成功后,调用相关函数生成token,并存入cookie:

public ResponseEntity<Map<String, Object>> userLogin(HttpServletResponse response, @RequestBody Worker worker) {Map<String, Object> res = new HashMap<>();Worker ret = loginService.userLogin(worker.getName(), worker.getPassword());if (ret != null) {// 登录成功String userId = ret.getPid() + "";String token = jwt.generateToken(userId); // 设置HttpOnly CookieResponseCookie cookie = ResponseCookie.from("userClientToken", token).httpOnly(true).secure(false) // 开发环境允许.path("/") // 全局路径有效.maxAge(8640).build();response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());res.put("code", 200);res.put("message", "登录成功");res.put("token", token);res.put("data", Map.of("userId", ret.getPid(), "username", ret.getName()));} else {res.put("code", 401);res.put("message", "用户名或密码错误");return ResponseEntity.status(401).body(res);}return ResponseEntity.ok(res);

token验证相关代码如下:

	@PostMapping("/api/validateToken")public ResponseEntity<Boolean> validateToken(HttpServletRequest request){Cookie[] cookies = request.getCookies();if (cookies == null) {System.out.print("没有cookie\n");return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();}String token = Arrays.stream(cookies).filter(c -> "userClientToken".equals(c.getName())).map(Cookie::getValue).findFirst().orElse(null);System.out.print("cookie验证\n");if (token == null || !jwt.validateToken(token)) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();}System.out.print("token有效\n");return ResponseEntity.ok().build();}
http://www.xdnf.cn/news/571789.html

相关文章:

  • sqli-labs第十八关——POST-UA注入
  • 使用MATLAB输出1000以内所有完美数
  • MoManipVLA-北京邮电-2025.3.17-移动操控-未完全开源
  • UML 时序图 使用案例
  • PostGIS实现栅格数据导出PNG应用实践【ST_AsPNG 】
  • 乘“4”而上,进取不止|Aloudata 的变与不变
  • 【专四 | 2022年真题】LANGUAGE USAGE逐题总结
  • dedecms织梦全局变量调用方法总结
  • 【OCCT+ImGUI系列】009-Geom2d-Geom2d_AxisPlacement
  • 使用Jenkins部署nodejs前端项目
  • 开源Vue表单设计器FcDesigner中组件联动的配置教程
  • 中国地图上标注颜色的方法
  • 食品饮料行业AI转型趋势分析与智能化解决方案探索​
  • 实战5:个性化数字艺术生成与销售
  • 目标检测 Lite-DETR(2023)详细解读
  • 信息系统项目管理师考前练习3
  • 怎样用 esProc 生成定长时间窗口列表并统计
  • 【Java高阶面经:微服务篇】7. 1秒响应保障:超时控制如何成为高并发系统的“救火队长”?
  • esp32cmini SK6812 2个方式
  • redis--redisJava客户端:Jedis详解
  • WebFuture:在银河麒麟系统中如何无中间件为WebFuture绑定域名、SSL证书
  • 【Linux】借助gcc源码修改,搜索头文件当前进展
  • springboot链接nacos测试
  • 分类预测 | Matlab实现PNN概率神经网络多特征分类预测
  • 数学实验(Matlab绘图基础)
  • 大量程粗糙度轮廓仪适用于哪些材质和表面?
  • 矿物绝缘加热电缆行业2025数据分析报告
  • 使用Gemini, LangChain, Gradio打造一个书籍推荐系统 (第一部分)
  • Dockerfile指令详解
  • 打卡第二十四天