我是靠谱客的博主 神勇世界,这篇文章主要介绍Security框架:如何使用CorsFilter解决前端跨域请求问题,现在分享给大家,希望可以做个参考。

项目情况

最近做的pmdb项目是前后端分离的, 由于测试的时候是前端与后端联调,所以出现了跨域请求的问题。

浏览器默认会向后端发送一个Options方式的请求,根据后端的响应来判断后端支持哪些请求方式,支持才会真正的发送请求。

CORS介绍

CORS(Cross-Origin Resource Sharing 跨源资源共享),当一个请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。

在日常的项目开发时会不可避免的需要进行跨域操作,而在实际进行跨域请求时,经常会遇到类似 No 'Access-Control-Allow-Origin' header is present on the requested resource.这样的报错。

这样的错误,一般是由于CORS跨域验证机制设置不正确导致的。

解决方案

注释:本项目使用的是SprintBoot+Security+JWT+Swagger

第一步

新建CorsFilter,在过滤器中设置相关请求头

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.handlecar.basf_pmdb_service.filter; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CorsFilter extends OncePerRequestFilter { //public class CorsFilter implements Filter { // static final String ORIGIN = "Origin"; protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // String origin = request.getHeader(ORIGIN); response.setHeader("Access-Control-Allow-Origin", "*");//* or origin as u prefer response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "PUT, POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); // response.setHeader("Access-Control-Allow-Headers", "content-type, authorization"); response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With, Authorization"); response.setHeader("XDomainRequestAllowed","1"); //使前端能够获取到 response.setHeader("Access-Control-Expose-Headers","download-status,download-filename,download-message"); if (request.getMethod().equals("OPTIONS")) // response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_NO_CONTENT); else filterChain.doFilter(request, response); } // @Override // public void doFilter(ServletRequest req, ServletResponse res, // FilterChain chain) throws IOException, ServletException { // // HttpServletResponse response = (HttpServletResponse) res; // //测试环境用【*】匹配,上生产环境后需要切换为实际的前端请求地址 // response.setHeader("Access-Control-Allow-Origin", "*"); // response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); // // response.setHeader("Access-Control-Max-Age", "0"); // // response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With, auth"); // // response.setHeader("Access-Control-Allow-Credentials", "true"); // // response.setHeader("XDomainRequestAllowed","1"); // chain.doFilter(req, res); // } // // @Override // public void destroy() { // } // // @Override // public void init(FilterConfig arg0) throws ServletException { // } }

注释:这里的Access-Control-Expose-Headers的请求头是为了使前端能够获得到后端在response中自定义的header,不设置的话,前端只能看到几个默认显示的header。我这里是在使用response导出Excel的时候将文件名和下载状态信息以自定义请求头的形式放在了response的header里。

第二步

在Security的配置文件中初始化CorsFilter的Bean

复制代码
1
2
3
4
@Bean public CorsFilter corsFilter() throws Exception { return new CorsFilter(); }

第三步

在Security的配置文件中添加Filter配置,和映射配置

复制代码
1
2
3
4
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll() // 除上面外的所有请求全部需要鉴权认证。 .and() 相当于标示一个标签的结束,之前相当于都是一个标签项下的内容 .anyRequest().authenticated().and() .addFilterBefore(corsFilter(), UsernamePasswordAuthenticationFilter.class)

附:该配置文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.handlecar.basf_pmdb_service.conf; import com.handlecar.basf_pmdb_service.filter.CorsFilter; import com.handlecar.basf_pmdb_service.filter.JwtAuthenticationTokenFilter; import com.handlecar.basf_pmdb_service.security.JwtTokenUtil; import com.handlecar.basf_pmdb_service.security.CustomAuthenticationProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; //import com.allcom.security.JwtTokenUtil; @Configuration //@EnableWebSecurity is used to enable Spring Security's web security support and provide the Spring MVC integration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private final CustomAuthenticationProvider customAuthenticationProvider; @Autowired public WebSecurityConfig(CustomAuthenticationProvider customAuthenticationProvider) { this.customAuthenticationProvider = customAuthenticationProvider; } @Override protected void configure(AuthenticationManagerBuilder auth) { auth.authenticationProvider(customAuthenticationProvider); } @Bean public JwtTokenUtil jwtTokenUtil(){ return new JwtTokenUtil(); } @Bean public CorsFilter corsFilter() throws Exception { return new CorsFilter(); } @Bean public JwtAuthenticationTokenFilter authenticationTokenFilterBean() { return new JwtAuthenticationTokenFilter(); } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity // 由于使用的是JWT,我们这里不需要csrf,不用担心csrf攻击 .csrf().disable() // 基于token,所以不需要session .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .authorizeRequests() //.antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 允许对于网站静态资源的无授权访问 .antMatchers( HttpMethod.GET, "/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js", "/webjars/springfox-swagger-ui/images/**","/swagger-resources/configuration/*","/swagger-resources",//swagger请求 "/v2/api-docs" ).permitAll() // 对于获取token的rest api要允许匿名访问 .antMatchers("/pmdbservice/auth/**","/pmdbservice/keywords/export3").permitAll() .antMatchers(HttpMethod.OPTIONS,"/**").permitAll() // 除上面外的所有请求全部需要鉴权认证。 .and() 相当于标示一个标签的结束,之前相当于都是一个标签项下的内容 .anyRequest().authenticated().and() .addFilterBefore(corsFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class); // 禁用缓存 httpSecurity.headers().cacheControl(); } }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持靠谱客。

最后

以上就是神勇世界最近收集整理的关于Security框架:如何使用CorsFilter解决前端跨域请求问题的全部内容,更多相关Security框架内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(116)

评论列表共有 0 条评论

立即
投稿
返回
顶部