SpringMVC跨域配置以及權限控制攔截跨域請求時的問題解決

背景

最近公司開始推行先後端分離的架構,因而不可避免的引入了跨域的問題,跨域的概念能夠參考大佬的博客,這裏就再也不贅述了。
做爲Java最流行框架之一的Spring其實已經幫咱們寫好了不少代碼,咱們只須要簡單配置一下便可,固然下面會提到仍是有一些不如人意的地方。
PS:本文沒有使用SpringBoothtml

SpringMVC跨域(cors)配置

全局配置

在SpringMVC的配置文件中添加以下配置便可前端

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

單個controller配置

註解能夠寫在類上也能夠寫在方法上java

@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把跨域處理的攔截器放到了最後一個,那麼咱們權限過濾的攔截器就是排在了跨域處理以前,若是一個請求是無權限的,那麼被攔截返回以後因爲沒有跨域處理,在前端展現的就是跨域失敗的提示。一樣的,你全部的攔截器的攔截返回都是跨域失敗的提示,這顯然是不合理的。web

解決

方法一

SpringMVC還支持基於filter的跨域處理,因爲filter的位置是在interceptor以前的,因此能夠完美解決上述問題。官方給出的一個例子以下:spring

@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

<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>
相關文章
相關標籤/搜索