Security框架:如何使用CorsFilter解决前端跨域请求问题

目录
  • 项目情况
  • CORS介绍
  • 解决方案

项目情况

最近做的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();
    }
}

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

(0)

相关推荐

  • SpringBoot+Spring Security无法实现跨域的解决方案

    SpringBoot+Spring Security无法实现跨域 未使用Security时跨域: import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springf

  • CorsFilter 过滤器解决跨域的处理

    CorsFilter 过滤器如何解决跨域 不多逼逼,直接贴代码,前端所有请求头都放在headers里面就行 @Component public class CorsFilter { //这里是前端请求头,那个跨域就添加到这里就行了 private static final String headers = "User-Agent,Cache-Control,Content-type,Date,Server,withCredentials," + "appversion&quo

  • Spring Security拦截器引起Java CORS跨域失败的问题及解决

    在已设置CORS的项目中加入Spring Security,导致跨域访问失败,一开始以为是设置错CORS的问题,后来才发现是因为Spring Security的拦截冲突引起的. (一) CORS介绍 CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing). 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制. response响应头 响应头字段名称 作用 Access-Contro

  • CORS跨域问题常用解决方法代码实例

    一 后端服务器使用过滤器 新建过滤器: /** * 解决跨域 */ public class AccessControlAllowOriginFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletR

  • 基于SpringBoot解决CORS跨域的问题(@CrossOrigin)

    一.关于跨域介绍 在前后分离的架构下,跨域问题难免会遇见比如,站点 http://domain-a.com 的某 HTML 页面通过 的 src 请求 http://domain-b.com/image.jpg. 网络上的许多页面都会加载来自不同域的CSS样式表,图像和脚本等资源. 出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求. 例如,XMLHttpRequest和Fetch API遵循同源策略. 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非

  • Security框架:如何使用CorsFilter解决前端跨域请求问题

    目录 项目情况 CORS介绍 解决方案 项目情况 最近做的pmdb项目是前后端分离的, 由于测试的时候是前端与后端联调,所以出现了跨域请求的问题. 浏览器默认会向后端发送一个Options方式的请求,根据后端的响应来判断后端支持哪些请求方式,支持才会真正的发送请求. CORS介绍 CORS(Cross-Origin Resource Sharing 跨源资源共享),当一个请求url的协议.域名.端口三者之间任意一与当前页面地址不同即为跨域. 在日常的项目开发时会不可避免的需要进行跨域操作,而在实

  • 利用Nginx代理如何解决前端跨域问题详析

    前言 Nginx(发音同"engine X")是异步框架的网页服务器,也可以用作反向代理.负载平衡器和HTTP缓存. 本文将讲述如何使用 Nginx 在 Web 前后端分离开发中实现路由的转发. Web 开发通常使用的是前后端分离的开发模式,即前端和后端分别进行开发,前端通过 Ajax 请求后端的接口,将获取数据将数据渲染到页面上.前端开发会使用脚手架搭建前端开发环境,其底层通常会启动一个本地服务器,通常使用的是 nodejs 的 Express 框架.而后端则是提供接口,一般是放在线

  • 跨域浏览器设置解决前端跨域问题

    目录 一.什么是跨域 二.什么情况下会出现跨域 三.uni-app 项目 解决跨域办法 四.Vue.js 项目 解决跨域办法 五.终极解决办法,删除浏览器跨域限制 一.什么是跨域 出于浏览器的同源策略限制.同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.知识点:跨域只会出现在浏览器上,小程序和APP开发不会有跨域问题 二.什么情况下会出现跨域 说人话就是域名不同的时候会出现跨域.下面以 百度 域名为例,在域名的:协议.主机名.域名.

  • 完美解决axios跨域请求出错的问题

    错误信息: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 403

  • springboot 如何解决cross跨域请求的问题

    目录 springboot 解决cross跨域请求 1.使用ajax发送跨域请求接口时 2.在被跨域请求的一方配置 3.再次测试 4.对于只有个别需要开放跨域请求的接口可以这样玩 5.其它解决跨域请求的常用方法 Spring解决cross domain Spring4: Spring3旧版本: springboot 解决cross跨域请求 1.使用ajax发送跨域请求接口时 接口能正常接收到请求并响应,但是无法正常展示响应数据.跨域请求时会在有一个特别的请求头origin(请求来源). 浏览器认

  • 解决ajax跨域请求数据cookie丢失问题

    前端: 以jquery为例: 需要加入 复制代码 代码如下: xhrFields: {             withCredentials: true         },         crossDomain: true, $.ajax({         type: postType,         url: url,         data: postData || '',         xhrFields: {             withCredentials: tru

  • 完美解决ajax跨域请求下parsererror的错误

    ajax请求报parsererror错误是很宽泛的概念,很多情况下都报这个错, 在很多时候,即使ajax提交.返回都正常 XMLHttpRequest.status=200  (正常响应) XMLHttpRequest.readyState=4 (正常接收) ajax也会提示一个parseerror的错误. 出现这个错误,大都是不良书写习惯,或者语法不当造成的. 关于ajax的错误,请使用: error:function(XMLHttpRequest, textStatus, errorThro

  • 利用SpringMVC过滤器解决vue跨域请求的问题

    之前写过通过注释的方法解决跨域请求的方法,需要每次都在controll类使用注解,这次通过springmvc的拦截器解决: 继承SpringMVC的类HandlerInterceptor重写preHandle方法,这个方法会在到达 controll之前调用,如下 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

  • React如何解决fetch跨域请求时session失效问题

    前言 fetch在reactjs中等同于 XMLHttpRequest,它提供了许多与XMLHttpRequest相同的功能,但被设计成更具可扩展性和高效性. Fetch 的核心在于对 HTTP 接口的抽象,包括 Request,Response,Headers,Body,以及用于初始化异步请求的 global fetch.得益于 JavaScript 实现的这些抽象好的 HTTP 模块,其他接口能够很方便的使用这些功能:除此之外,Fetch 还利用到了请求的异步特性--它是基于 Promise

  • springboot+jsonp解决前端跨域问题小结

    现在咱们一起来讨论浏览器跨域请求数据的相关问题.说这样可能不是很标准,因为拒绝跨域请求数据并不是浏览器所独有的,之所以会出现跨域请求不了数据,是因为浏览器基本都实现了一个叫"同源策略"的安全规范.该规范具体是什么呢?我们在MDN上找到了一份资料,地址如下: 浏览器同源策略讲解 总的来说,当A网址和B网址在 协议 . 端口 . 域名 方面存在不同时,浏览器就会启动同源策略,拒绝A.B服务器之间进行数据请求. 说了同源策略,纸上得来终觉浅,绝知此事要躬行,到底同源策略是怎么体现的呢?下面我

随机推荐