Shiro过滤器导致的前端跨域

在前后端分离的项目中,加入自定义请求头引发跨域问题。Shiro的过滤器在处理非简单请求时未正确处理,导致前端请求失败。通过重写过滤器的doFilter方法并处理重定向时请求头清空的问题,成功解决了Shiro引起的跨域难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题背景

公司项目是前后端分离的,最近要求在请求时都要在请求头加入自定义的 token,在做接口调试时,前端总是请求不通,然而自己用 POSTMAN 等工具时都可以,这就出现了问题,也就是 复杂请求 的跨域问题。

问题分析

部分文段摘自 跨域资源共享 CORS 详解

复杂请求

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

  • 请求方法是以下三种方法之一:
    HEAD
    GET
    POST
  • HTTP的头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type: 只限于三个值 application/x-www-form-urlencoded multipart/form-data text/plain
    这是为了兼容表单(form),因为历史上表单一直可以发出跨域请求。AJAX 的跨域设计就是,只要表单可以发,AJAX 就可以直接发。

凡是不同时满足上面两个条件,就属于非简单请求。

预检请求

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

过滤器

由于项目中的 shiro 使用了 UserFilter, 下面是其代码:

public class UserFilter extends AccessControlFilter {
    public UserFilter() {
  
### 使用Apache Shiro实现CORS资源共享 在Web应用程序中,资源共享(CORS, Cross-Origin Resource Sharing)是一个常见的需求。当客户端请求来自不同的名、协议或端口时,默认情况下浏览器会阻止这些请求以保护用户安全。为了使服务器能够响应不同源的HTTP请求并允许特定的操作,可以通过配置Apache Shiro来解决这个问题。 #### 配置Shiro Filter Chain定义中的自定义过滤器 为了让Shiro支持CORS,在`shiro.ini`文件或其他形式的FilterChainDefinitionMap里加入一个新的过滤器用于处理预检请求以及设置响应头: ```ini [main] corsFilter = org.apache.shiro.web.filter.authc.CorsFilter [urls] /** = corsFilter ``` 这段代码创建了一个名为`corsFilter`的对象实例化为`org.apache.shiro.web.filter.authc.CorsFilter`类,并将其应用到所有的URL路径上[^1]。 #### 自定义CorsFilter类 由于默认的Shiro并没有提供现成的支持CORS功能的过滤器,因此需要编写自己的过滤器逻辑。下面给出一个简单的例子展示如何构建这样一个过滤器: ```java import javax.servlet.Filter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; HttpServletRequest request= (HttpServletRequest)req; // 设置允许哪些来源可以访问资源 response.setHeader("Access-Control-Allow-Origin", "*"); // 设置允许的方法类型 response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); // 设置允许携带的头部信息 response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "authorization, content-type," + "access-control-request-headers, access-control-request-method, accept"); if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } } ``` 此段Java代码实现了对所有传入请求添加必要的CORS响应头字段,从而使得前端可以从其他发起AJAX调用而不会被同源策略所阻挡。对于预飞行(Preflight)请求即方法为`OPTIONS`的情况,则直接返回成功状态码而不行后续操作;而对于正常的业务请求则继续传递给下一个过滤器或目标Servlet进行处理[^2]。 #### 注册自定义过滤器至Spring容器(如果适用) 如果是基于Spring的应用程序,还可以将上面提到的`CorsFilter`注册成为Bean以便于管理和依赖注入: ```xml <bean id="corsFilter" class="com.example.security.CorsFilter"/> <!-- 或者使用注解方式 --> @Component public class CorsFilter {...} ``` 接着更新`web.xml`或者对应的Spring MVC配置文件让其知道新加入的过滤器的存在: ```xml <filter> <filter-name>cors</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>corsFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>cors</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` 这样就完成了整个流程——从理解问题背景到最后的具体实施步骤都涵盖了进来,确保了方案的有效性和完整性[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值