package com.interceptor;
import java.io.IOException;
import java.io.PrintWriter;
import com.alibaba.fastjson.JSONObject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import com.annotation.IgnoreAuth;
import com.entity.TokenEntity;
import com.service.TokenService;
import com.utils.R;
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
public static final String LOGIN_TOKEN_KEY = "Token";
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// ========== 1. 先设置跨域响应头 ==========
String origin = request.getHeader("Origin");
if (StringUtils.isNotBlank(origin)) {
response.setHeader("Access-Control-Allow-Origin", origin);
} else {
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8082");
}
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization");
// ========== 2. 放行 OPTIONS 预检请求 ==========
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return true; // ← 改这里
}
// ========== 3. Token 校验逻辑 ==========
IgnoreAuth annotation;
if (handler instanceof HandlerMethod) {
annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
} else {
return true;
}
String token = request.getHeader(LOGIN_TOKEN_KEY);
if (annotation != null) {
return true;
}
TokenEntity tokenEntity = null;
if (StringUtils.isNotBlank(token)) {
tokenEntity = tokenService.getTokenEntity(token);
}
if (tokenEntity != null) {
request.getSession().setAttribute("userId", tokenEntity.getUserid());
request.getSession().setAttribute("role", tokenEntity.getRole());
request.getSession().setAttribute("tableName", tokenEntity.getTablename());
request.getSession().setAttribute("username", tokenEntity.getUsername());
return true;
}
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try {
writer = response.getWriter();
writer.print(JSONObject.toJSONString(R.error(401, "请先登录")));
} finally {
if (writer != null) {
writer.close();
}
}
return false;
}
}
跨域问题不知道怎么解决(语言-java)
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
2条回答 默认 最新
檀越@新空间 2026-04-13 05:30关注上午好☀️☀️☀️️
本答案参考通义千问跨域问题(CORS, Cross-Origin Resource Sharing)是前端与后端进行通信时常见的问题,尤其是在前后端分离的架构中。你提供的代码是一个 Spring Boot 的拦截器类
AuthorizationInterceptor,用于处理 Token 验证和跨域配置。但是当前的跨域设置方式存在一些 不规范 和 潜在的问题,需要进行优化。
✅ 一、为什么会出现跨域问题?
当你的前端应用(例如部署在
http://localhost:8082)请求后端服务(例如部署在http://localhost:8081),浏览器会根据同源策略判断是否允许该请求。如果 域名、协议或端口不同,就会触发 CORS 预检请求(OPTIONS),并要求后端返回相应的响应头信息。
✅ 二、当前代码中的跨域配置问题
你目前的跨域配置是在
preHandle方法中手动设置的响应头,但这种做法有以下 问题:- 不规范:Spring Boot 提供了更标准的 CORS 配置方式。
- 无法处理 OPTIONS 请求:虽然你对 OPTIONS 请求做了处理,但可能没有完全覆盖所有情况。
- 动态 Origin 设置不稳定:使用
request.getHeader("Origin")来动态设置Access-Control-Allow-Origin可能导致安全风险。 - 无法处理复杂请求(如 Cookie、认证等):需要额外设置
Access-Control-Allow-Credentials等字段。
✅ 三、推荐解决方案(标准做法)
🔧 方案 1:通过
@CrossOrigin注解全局设置(适用于简单项目)如果你的项目规模较小,可以在主类或 Controller 上添加注解:
@SpringBootApplication @CrossOrigin(origins = "http://localhost:8082", allowCredentials = "true") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }📌 注意:这种方式只适用于简单的接口,不适合复杂的场景。
🔧 方案 2:通过
WebMvcConfigurer全局配置 CORS(推荐)这是最标准的做法,适用于大多数 Spring Boot 项目。
步骤 1:创建一个配置类
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:8082") // 允许的来源 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的方法 .allowedHeaders("*") // 允许的请求头 .exposedHeaders("Token") // 暴露给客户端的响应头 .allowCredentials(true); // 是否允许凭证(Cookie) } }📌 重点说明:
allowedOrigins是你前端的地址,可以是多个(用逗号分隔)。allowCredentials必须设为true,如果你的请求中包含 Cookie 或 Token。- 如果你使用了 JWT 或其他 Token 认证,确保
Token响应头被正确暴露。
🔧 方案 3:修改你的拦截器逻辑(如果必须保留)
如果你确实要通过拦截器处理跨域,建议优化如下:
修改后的
AuthorizationInterceptor代码:@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // ========== 1. 跨域配置(推荐统一通过 WebMvcConfigurer 处理) ========== String origin = request.getHeader("Origin"); if (StringUtils.isNotBlank(origin)) { response.setHeader("Access-Control-Allow-Origin", origin); } else { response.setHeader("Access-Control-Allow-Origin", "http://localhost:8082"); } response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization"); // ========== 2. 放行 OPTIONS 预检请求 ========== if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); return true; } // ========== 3. Token 校验逻辑(保持不变) ========== IgnoreAuth annotation; if (handler instanceof HandlerMethod) { annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class); } else { return true; } String token = request.getHeader(LOGIN_TOKEN_KEY); if (annotation != null) { return true; } TokenEntity tokenEntity = null; if (StringUtils.isNotBlank(token)) { tokenEntity = tokenService.getTokenEntity(token); } if (tokenEntity != null) { request.getSession().setAttribute("userId", tokenEntity.getUserid()); request.getSession().setAttribute("role", tokenEntity.getRole()); request.getSession().setAttribute("tableName", tokenEntity.getTablename()); request.getSession().setAttribute("username", tokenEntity.getUsername()); return true; } PrintWriter writer = null; response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); try { writer = response.getWriter(); writer.print(JSONObject.toJSONString(R.error(401, "请先登录"))); } finally { if (writer != null) { writer.close(); } } return false; }⚠️ 注意:
- 不推荐在拦截器中处理跨域,因为这可能导致重复设置响应头,或者在某些情况下失效。
- 如果你仍然希望在拦截器中处理跨域,请确保 只在预检请求中处理,避免干扰正常业务逻辑。
✅ 四、总结:推荐做法
| 方案 | 推荐程度 | 说明 | |------|----------|------| | 使用
@CrossOrigin注解 | 中 | 适合小型项目,简单快捷 | | 使用WebMvcConfigurer配置 CORS | ⭐⭐⭐⭐⭐ | 最标准、最推荐的方式 | | 在拦截器中处理跨域 | ❌ | 不推荐,容易出错 |
✅ 五、最终建议
强烈建议你采用方案 2:通过
WebMvcConfigurer全局配置 CORS。这样不仅能够统一管理跨域规则,还能保证安全性、可维护性和性能。同时,它不会干扰你的 Token 验证逻辑。
如有更多关于 Token 认证或跨域的疑问,欢迎继续提问!
解决 无用评论 打赏 举报