文档章节

SpringMVC跨域配置以及权限控制拦截跨域请求时的问题解决

司徒无涯
 司徒无涯
发布于 2018/09/29 11:32
字数 936
阅读 1274
收藏 9

背景

最近公司开始推行前后端分离的架构,于是不可避免的引入了跨域的问题,跨域的概念可以参考大佬的博客,这里就不再赘述了。
作为Java最流行框架之一的Spring其实已经帮我们写好了很多代码,我们只需要简单配置一下即可,当然下面会提到还是有一些不如人意的地方。
PS:本文没有使用SpringBoot

SpringMVC跨域(cors)配置

全局配置

在SpringMVC的配置文件中添加如下配置即可

<mvc:cors>
	<mvc:mapping path="/**" allow-credentials="true" allowed-methods="*" allowed-headers="*" allowed-origins="*"/>
</mvc:cors>

单个controller配置

注解可以写在类上也可以写在方法上

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin("http://domain2.com")
	@RequestMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

加上权限控制后踩坑

原因

一般我们使用的都是全局的配置,而SpringMVC把跨域处理的拦截器放到了最后一个,那么我们权限过滤的拦截器就是排在了跨域处理之前,如果一个请求是无权限的,那么被拦截返回之后由于没有跨域处理,在前端展示的就是跨域失败的提示。同样的,你所有的拦截器的拦截返回都是跨域失败的提示,这显然是不合理的。

解决

方法一

SpringMVC还支持基于filter的跨域处理,由于filter的位置是在interceptor之前的,所以可以完美解决上述问题。官方给出的一个例子如下:

@Configuration
public class MyConfiguration {

	@Bean
	public FilterRegistrationBean corsFilter() {
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		CorsConfiguration config = new CorsConfiguration();
		config.setAllowCredentials(true);
		config.addAllowedOrigin("http://domain1.com");
		config.addAllowedHeader("*");
		config.addAllowedMethod("*");
		source.registerCorsConfiguration("/**", config);
		FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
		bean.setOrder(0);
		return bean;
	}
}

方法二

方法一有个比较坑的地方就是FilterRegistrationBean这个类只有SpringBoot中才有,那我们项目没有用SpringBoot咋办,下边是常规配置的方法:

<!-- 这个配置需要放到Spring的配置文件中,不能放到SpringMVC的配置文件,因为SpringMVC的加载是基于Servlet,它是晚于Filter的 -->
<bean id="corsFilter" class="org.springframework.web.filter.CorsFilter">
    <constructor-arg name="configSource">
        <bean class="org.springframework.web.cors.UrlBasedCorsConfigurationSource">
            <property name="corsConfigurations">
                <map>
                    <entry key="/**">
                        <bean class="org.springframework.web.cors.CorsConfiguration">
                            <property name="allowCredentials" value="true"/>
                            <property name="allowedMethods">
                                <list>
                                    <value>GET</value>
                                    <value>POST</value>
                                    <value>HEAD</value>
                                </list>
                            </property>
                            <property name="allowedHeaders" value="*"/>
                            <property name="allowedOrigins" value="*"/>
                        </bean>
                    </entry>
                </map>
            </property>
        </bean>
    </constructor-arg>
</bean>

由于CorsFilter跟通常的Filter不一样,Spring对其做了很多改造,所以加载的方式要使用DelegatingFilterProxy,通过Spring的方式把它放到容器中

<!-- web.xml -->
<filter>
    <filter-name>myCorsFilter</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>myCorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

方法三

除了使用Spring提供的方法,你也可以自己编写跨域的处理,因为跨域的处理其实就是在响应头里加一些东西

public class CorsInterceptor extends HandlerInterceptorAdapter {

	//@Setter是lombok的注解,等价于setter方法,下同
    @Setter
    private String allowCredentials;

    @Setter
    private String allowedMethods;

    @Setter
    private String allowedHeaders;

    @Setter
    private String allowedOrigins;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("Adding Access Control Response Headers");
        if (CorsUtils.isCorsRequest(request)) {
            ServletServerHttpRequest wrapRequest = new ServletServerHttpRequest(request);
            if(CorsConfiguration.ALL.equals(allowedOrigins)) {
                response.setHeader("Access-Control-Allow-Origin", wrapRequest.getHeaders().getOrigin());
            } else {
                response.setHeader("Access-Control-Allow-Origin", allowedOrigins);
            }
            response.setHeader("Access-Control-Allow-Credentials", allowCredentials);
            response.setHeader("Access-Control-Allow-Methods", allowedMethods);
            response.setHeader("Access-Control-Allow-Headers", allowedHeaders);
        }
        return true;
    }
}

SpringMVC配置

<mvc:interceptors>
	<mvc:interceptor>
		<mvc:mapping path="/**/*.do"/>
		<bean class="com.fingard.gardpay.websys.web.interceptor.CorsInterceptor">
			<property name="allowCredentials" value="true"/>
			<property name="allowedHeaders" value="*"/>
			<property name="allowedMethods" value="GET,POST,HEAD,OPTIONS"/>
			<property name="allowedOrigins" value="*"/>
		</bean>
	</mvc:interceptor>
</mvc:interceptors>

© 著作权归作者所有

司徒无涯
粉丝 11
博文 68
码字总数 60347
作品 0
杭州
程序员
私信 提问
SpringMVC拦截器Interceptor导致跨越cors失效

项目采用前后端分离,服务器端添加了全局的跨域配置,但是却出现了跨域问题,分析了多次请求发现有一部分请求并没有出现跨域,没有出现跨域的请求刚好就是拦截器放行的地址,所以分析可能是权...

皮皮猫32
04/12
89
0
Spring @CrossOrigin 注解原理

现实开发中,我们难免遇到跨域问题,以前笔者只知道jsonp这种解决方式,后面听说spring只要加入@CrossOrigin即可解决跨域问题。本着好奇的心里,笔者看了下@CrossOrigin 作用原理,写下这篇博...

暗中观察
03/13
658
0
Java服务端Cors跨域资源共享配置,解决与Spring Security冲突引起的问题

(一) CORS介绍 CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。 re...

hhjian
2017/11/01
382
0
SpringBoot +spring security 与CSRF有关的几个 问题

1、问题 开启 csrf 后 列表页面没有数据 页面console.log(403) 2、科普 首先,科普一下,什么是"CSRF"? 这是一个web应用安全的问题,CSRF(Cross-site request forgery)跨站请求伪造,也被称...

douruanliang
2018/05/15
0
0
Spring 跨域支持(CROS)注解:@CrossOrigin

Spring MVC 4.2 增加 CORS 支持 跨站 HTTP 请求(Cross-site HTTP request)是指发起请求的资源所在域不同于该请求所指向资源所在的域的 HTTP 请求。比如说,域名A(http://domaina.example)的某...

孟飞阳
2017/11/08
307
0

没有更多内容

加载失败,请刷新页面

加载更多

java通过ServerSocket与Socket实现通信

首先说一下ServerSocket与Socket. 1.ServerSocket ServerSocket是用来监听客户端Socket连接的类,如果没有连接会一直处于等待状态. ServetSocket有三个构造方法: (1) ServerSocket(int port);...

Blueeeeeee
50分钟前
4
0
用 Sphinx 搭建博客时,如何自定义插件?

之前有不少同学看过我的个人博客(http://python-online.cn),也根据我写的教程完成了自己个人站点的搭建。 点此:使用 Python 30分钟 教你快速搭建一个博客 为防有的同学不清楚 Sphinx ,这...

王炳明
昨天
4
0
黑客之道-40本书籍助你快速入门黑客技术免费下载

场景 黑客是一个中文词语,皆源自英文hacker,随着灰鸽子的出现,灰鸽子成为了很多假借黑客名义控制他人电脑的黑客技术,于是出现了“骇客”与"黑客"分家。2012年电影频道节目中心出品的电影...

badaoliumang
昨天
13
0
很遗憾,没有一篇文章能讲清楚线程的生命周期!

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 简介 大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。 ...

彤哥读源码
昨天
14
0
jquery--DOM操作基础

本文转载于:专业的前端网站➭jquery--DOM操作基础 元素的访问 元素属性操作 获取:attr(name);$("#my").attr("src"); 设置:attr(name,value);$("#myImg").attr("src","images/1.jpg"); ......

前端老手
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部