前端请求总是失败说受跨域请求影响,但前后端配置已经没有问题了,如下:
package com.example.shop_manage_sys.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.example.shop_manage_sys.Interceptor.TokenInterceptor;@Configuration
public class CorsConfig implements WebMvcConfigurer {@Autowiredprivate TokenInterceptor jwtInterceptor;
//cors配置@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // Applies CORS to all paths.allowedOrigins("http://127.0.0.1:8081", "http://localhost:8081") // List specific allowed origins.allowedMethods("GET", "POST", "PUT", "DELETE","OPTIONS").allowedHeaders("accept", "content-type", "origin", "custom-header","token").allowCredentials(true).maxAge(3600); }
//拦截器配置@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor).addPathPatterns("/**").excludePathPatterns("/sms/*"); // 排除不需要拦截的路径}
}
后端获取前端请求头中自定义的token字段时获取到null,这是因为浏览器端会在请求前总发出一次预检请求,后端的拦截器将这种options请求直接放行即可。
示例拦截器代码:
package com.example.shop_manage_sys.Interceptor;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
// import org.springframework.web.servlet.ModelAndView;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;// import java.util.Base64;@Component
public class TokenInterceptor implements HandlerInterceptor {@Value("${jwt.secret}")private String SECRET_KEY;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {// 直接放行预检请求return true;}String token = request.getHeader("token");if (token != null && !token.isEmpty()) {try {// 验证并解析tokenKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8));Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);Claims claims = claimsJws.getBody();request.setAttribute("claims", claims);return true;} catch (Exception e) {handleJwtError(response, "Invalid or expired token.");return false;}} else {handleJwtError(response, "Token is missing.");return false;}}private void handleJwtError(HttpServletResponse response, String errorMessage) {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.setCharacterEncoding(StandardCharsets.UTF_8.name());try {// Wrap the ServletOutputStream in a ServletServerHttpResponseServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);// Convert the JSON string to an ObjectObject jsonContent = "{\"error\": \"" + errorMessage + "\"}";// Write the JSON content to the output streamnew MappingJackson2HttpMessageConverter().write(jsonContent, MediaType.APPLICATION_JSON, outputMessage);} catch (Exception e) {e.printStackTrace();}}// 你可以选择性实现以下方法,但在这个场景下它们可能不是必须的// @Override// public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {// // ...// }//// @Override// public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {// // ...// }
}