Security框架:如何使用CorsFilter解决前端跨域请求问题
程序员文章站
2022-03-10 20:36:08
目录项目情况cors介绍解决方案项目情况最近做的pmdb项目是前后端分离的, 由于测试的时候是前端与后端联调,所以出现了跨域请求的问题。浏览器默认会向后端发送一个options方式的请求,根据后端的响...
项目情况
最近做的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,在过滤器中设置相关请求头
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
@bean public corsfilter corsfilter() throws exception { return new corsfilter(); }
第三步
在security的配置文件中添加filter配置,和映射配置
.antmatchers(httpmethod.options,"/**").permitall() // 除上面外的所有请求全部需要鉴权认证。 .and() 相当于标示一个标签的结束,之前相当于都是一个标签项下的内容 .anyrequest().authenticated().and() .addfilterbefore(corsfilter(), usernamepasswordauthenticationfilter.class)
附:该配置文件
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(); } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
下一篇: js数据呈现案例