设置header,实现跨域访问

受浏览器的同源策略限制,JavaSript只能请求本域内的资源。跨域资源共享(Cross-Origin Resource Sharing, CORS)是为解决Ajax技术难实现跨域问题而提出的一个规范,这个规范试着从根本上解决安全的跨域资源共享问题。在此之前,解决此类问题的途径往往是服务器代理、JSONP等,治标不治本。目前基本所有浏览器都已经支持该规范。

一个域是由schema、host、port三者共同组成,与路径无关。所谓跨域,是指在http://example-foo.com/域上通过XMLHttpRequest对象调用http://example-bar.com/域上的资源。CORS约定服务器端和浏览器在HTTP协议之上,通过一些额外HTTP头部信息,进行跨域资源共享的协商。服务器端和浏览器都必需遵循规范中的要求。

CORS把HTTP请求分成两类,不同类别按不同的策略进行跨域资源共享协商。

1. 简单跨域请求。
当HTTP请求出现以下两种情况时,浏览器认为是简单跨域请求:

1). 请求方法是GET、HEAD或者POST,并且当请求方法是POST时,Content-Type必须是application/x-www-form-urlencoded, multipart/form-data或着text/plain中的一个值。
2). 请求中没有自定义HTTP头部。

对于简单跨域请求,浏览器要做的就是在HTTP请求中添加Origin Header,将JavaScript脚本所在域填充进去,向其他域的服务器请求资源。服务器端收到一个简单跨域请求后,根据资源权限配置,在响应头中添加Access-Control-Allow-Origin Header。浏览器收到响应后,查看Access-Control-Allow-Origin Header,如果当前域已经得到授权,则将结果返回给JavaScript。否则浏览器忽略此次响应。

2. 带预检(Preflighted)的跨域请求。
当HTTP请求出现以下两种情况时,浏览器认为是带预检(Preflighted)的跨域请求:

1). 除GET、HEAD和POST(only with application/x-www-form-urlencoded, multipart/form-data, text/plain Content-Type)以外的其他HTTP方法。
2). 请求中出现自定义HTTP头部。

带预检(Preflighted)的跨域请求需要浏览器在发送真实HTTP请求之前先发送一个OPTIONS的预检请求,检测服务器端是否支持真实请求进行跨域资源访问,真实请求的信息在OPTIONS请求中通过Access-Control-Request-Method Header和Access-Control-Request-Headers Header描述,此外与简单跨域请求一样,浏览器也会添加Origin Header。服务器端接到预检请求后,根据资源权限配置,在响应头中放入Access-Control-Allow-Origin Header、Access-Control-Allow-Methods和Access-Control-Allow-Headers Header,分别表示允许跨域资源请求的域、请求方法和请求头。此外,服务器端还可以加入Access-Control-Max-Age Header,允许浏览器在指定时间内,无需再发送预检请求进行协商,直接用本次协商结果即可。浏览器根据OPTIONS请求返回的结果来决定是否继续发送真实的请求进行跨域资源访问。这个过程对真实请求的调用者来说是透明的。

XMLHttpRequest支持通过withCredentials属性实现在跨域请求携带身份信息(Credential,例如Cookie或者HTTP认证信息)。浏览器将携带Cookie Header的请求发送到服务器端后,如果服务器没有响应Access-Control-Allow-Credentials Header,那么浏览器会忽略掉这次响应。

这里讨论的HTTP请求是指由Ajax XMLHttpRequest对象发起的,所有的CORS HTTP请求头都可由浏览器填充,无需在XMLHttpRequest对象中设置。以下是CORS协议规定的HTTP头,用来进行浏览器发起跨域资源请求时进行协商:
1. Origin。HTTP请求头,任何涉及CORS的请求都必需携带。
2. Access-Control-Request-Method。HTTP请求头,在带预检(Preflighted)的跨域请求中用来表示真实请求的方法。
3. Access-Control-Request-Headers。HTTP请求头,在带预检(Preflighted)的跨域请求中用来表示真实请求的自定义Header列表。
4. Access-Control-Allow-Origin。HTTP响应头,指定服务器端允许进行跨域资源访问的来源域。可以用通配符*表示允许任何域的JavaScript访问资源,但是在响应一个携带身份信息(Credential)的HTTP请求时,Access-Control-Allow-Origin必需指定具体的域,不能用通配符。
5. Access-Control-Allow-Methods。HTTP响应头,指定服务器允许进行跨域资源访问的请求方法列表,一般用在响应预检请求上。
6. Access-Control-Allow-Headers。HTTP响应头,指定服务器允许进行跨域资源访问的请求头列表,一般用在响应预检请求上。
7. Access-Control-Max-Age。HTTP响应头,用在响应预检请求上,表示本次预检响应的有效时间。在此时间内,浏览器都可以根据此次协商结果决定是否有必要直接发送真实请求,而无需再次发送预检请求。
8. Access-Control-Allow-Credentials。HTTP响应头,凡是浏览器请求中携带了身份信息,而响应头中没有返回Access-Control-Allow-Credentials: true的,浏览器都会忽略此次响应。

### 使用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]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值