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

背景

最近公司开始推行前后端分离的架构,于是不可避免的引入了跨域的问题,跨域的概念可以参考大佬的博客,这里就不再赘述了。
作为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>

转载于:https://my.oschina.net/icebergxty/blog/2221404

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值