拦截器拦截options请求,导致无法获得自定义的请求头

该博客介绍了如何在Spring MVC中实现一个权限拦截器`AuthInterceptors`,通过检查请求头中的`x-token`来验证用户权限。在预处理方法`preHandle`中,首先获取请求头的所有信息,然后针对OPTIONS请求直接返回成功状态,对于其他请求则调用`Varifcation`服务进行令牌验证。如果验证通过,则允许请求继续,否则拒绝访问。
package com.qyc.interceptor;

import com.qyc.cfg.SpringContextUtils;
import com.qyc.service.Varifcation;
import org.apache.ibatis.plugin.Intercepts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;


public class AuthInterceptors implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //参数
        Enumeration<String> headerNames = request.getHeaderNames();
                while (headerNames.hasMoreElements()) {
                        String name = headerNames.nextElement();
                       //根据名称获取请求头的值
                    String value = request.getHeader(name);
                       System.out.println(name+"---"+value);
                   }
        if (request.getMethod().equals("OPTIONS")) {
            response.setStatus(HttpServletResponse.SC_OK);
            System.out.println("进入判断"+request.getMethod());
            return true;
        }
        String token = request.getHeader("x-token");
        Varifcation varifcation = (Varifcation) SpringContextUtils.getBeanByClass(Varifcation.class);
        System.out.println("tokeninin ======== " + token);
        boolean mess = varifcation.verifyToken(token);
        return mess;
    }
}

原因:https://blog.csdn.net/qq_38261174/article/details/90691058

<think>好的,我现在需要解决用户的问题:如何处理拦截器中预检请求OPTIONS没有携带token导致请求失败的情况。用户提到他们的拦截器在预检请求时因为缺少token而拦截请求导致后续的真实请求无法通过。 首先,我需要回忆一下关于跨域请求和预检请求的知识。根据引用[4],跨域请求中的复杂方法或特殊头会触发浏览器发送OPTIONS预检请求。这个预检请求本身不携带任何认证信息,比如token,所以如果拦截器检查到缺少token而拦截OPTIONS请求,就会导致后续的真实请求被浏览器阻止。 接下来,我需要分析用户的配置。用户提到他们使用了自定义拦截器,可能在Spring框架中,同时还有Spring Security的拦截。根据引用[3],Spring Security可能会拦截OPTIONS请求,并且因为没有token而返回401,导致预检失败。所以问题可能出在拦截器没有正确处理OPTIONS方法,直接进行了token验证。 解决方案的关键点在于区分预检请求和实际请求OPTIONS请求的HTTP方法是OPTIONS,所以拦截器中应该先检查请求的方法。如果是OPTIONS,应该直接放行,不进行token验证。这样可以允许预检请求通过,之后浏览器发送的真实请求(如GET、POST)才会携带token,这时候再进行验证。 另外,用户可能需要在Spring Security的配置中允许OPTIONS请求的访问。例如,配置忽略OPTIONS请求的安全检查,或者设置跨域配置(CORS)来正确处理预检请求。比如,使用CorsConfigurationSource来定义允许的来源、头和方法,这样Spring Security会自动处理OPTIONS请求,而无需经过拦截器的token检查。 还需要考虑拦截器的执行顺序。如果自定义拦截器在Spring Security之前执行,可能需要调整顺序,或者确保在拦截器中正确处理OPTIONS方法。例如,在拦截器的preHandle方法中,判断如果是OPTIONS请求则返回true,直接放行。 用户提到的引用[2]中,sa-token框架的问题也是类似的,需要确保预检请求不被拦截。所以可能的解决步骤是: 1. 修改拦截器逻辑,对OPTIONS请求放行。 2. 配置Spring Security允许OPTIONS请求。 3. 设置正确的CORS策略,确保服务器响应包含必要的头信息,如Access-Control-Allow-Origin等。 在代码实现方面,拦截器中的preHandle方法需要添加对请求方法的判断。例如,在Java中: ```java if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { return true; } ``` 同时,在Spring Security的配置类中,配置CORS并允许OPTIONS方法: ```java @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.cors().configurationSource(corsConfigurationSource()) .and() // 其他配置... return http.build(); } private CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("http://localhost:8080")); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } ``` 这样,预检请求会被CORS配置处理,而不会被拦截器拦截。同时,拦截器OPTIONS请求放行后,后续的真实请求携带token时才会被验证,避免被拦截。 还需要测试这些修改是否有效,确保预检请求返回200状态码,并且真实请求携带token后能正常通过拦截器。另外,要确认CORS头是否正确设置,避免其他跨域问题。 可能的问题包括:拦截器的顺序是否正确,CORS配置是否覆盖了所有需要的路径,是否漏掉了某些HTTP方法或头信息。需要确保配置的全面性,例如允许所有必要的方法和头,或者根据实际需求进行限制。 总结来说,解决这个问题的核心在于识别并放行OPTIONS预检请求,同时正确配置CORS策略,确保服务器正确处理跨域请求,避免拦截器在预检阶段进行不必要的验证。</think>### 解决方案 处理预检请求拦截问题的核心思路是**区分OPTIONS预检请求和实际请求**,通过以下三个步骤实现: --- ### 一、拦截器中放行OPTIONS请求自定义拦截器的`preHandle`方法中添加对请求方法的判断: ```java public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 放行所有OPTIONS请求 if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { return true; // 直接放行不验证 } // 其他请求需验证Token String token = request.getHeader("Authorization"); if (token == null || !validateToken(token)) { sendError(response, 401); return false; } return true; } ``` --- ### 二、配置Spring Security允许OPTIONS请求 在Spring Security配置类中明确放行OPTIONS请求: ```java @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeRequests() .requestMatchers(HttpMethod.OPTIONS).permitAll() // 关键配置 .anyRequest().authenticated() .and() .cors().configurationSource(corsConfigurationSource()) .and() .csrf().disable(); return http.build(); } ``` --- ### 三、配置CORS策略 通过CorsConfigurationSource定义跨域规则: ```java private CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("http://your-frontend-domain.com")); config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); config.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); config.setAllowCredentials(true); config.setMaxAge(3600L); // 预检结果缓存1小时 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } ``` --- ### 技术原理 1. **预检请求机制**:浏览器对跨域复杂请求自动发送OPTIONS预检请求,该请求不含业务参数或Token[^4] 2. **拦截器优先级**:确保Spring Security的CORS配置优先于自定义拦截器执行[^3] 3. **缓存优化**:通过`MaxAge`减少重复预检请求,提升性能[^4] --- ### 验证流程 1. 浏览器发送OPTIONS预检请求 → 服务器返回200并携带CORS头 2. 浏览器发送真实请求(GET/POST等) → 携带Token → 拦截器验证通过 3. 若Token无效 → 返回401拒绝访问 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值