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

 更新时间:2021年11月16日 08:44:45   作者:我滴太阳233  
这篇文章主要介绍了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,在过滤器中设置相关请求头

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();
    } 
}

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

相关文章

  • 一文带你了解Java中IO流与Guava的使用

    一文带你了解Java中IO流与Guava的使用

    Java为我们提供了非常多的操作IO的接口与类,帮助开发者实现不同源间的数据传输,比如硬盘文件、网络传输、应用调用间的数据交互与传递。今天我们来简单了解下Java中的流 以及在Guava工具包中,针对IO操作做了什么样的封装与设计
    2022-11-11
  • 使用ByteArrayOutputStream写入字符串方式

    使用ByteArrayOutputStream写入字符串方式

    这篇文章主要介绍了使用ByteArrayOutputStream写入字符串方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Java用list储存,遍历,查询指定信息过程详解

    Java用list储存,遍历,查询指定信息过程详解

    这篇文章主要介绍了Java用list储存,遍历,查询指定信息过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • MyBatis传入多个参数时parameterType的写法

    MyBatis传入多个参数时parameterType的写法

    这篇文章主要介绍了MyBatis传入多个参数时parameterType的写法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • 深入了解Java对象的克隆

    深入了解Java对象的克隆

    这篇文章主要介绍了Java对象的克隆的相关资料,帮助大家更好的理解和学习Java,感兴趣的朋友可以了解下
    2020-08-08
  • 运行java的class文件方法详解

    运行java的class文件方法详解

    这篇文章主要详细介绍了运行java的class文件方法的相关资料,需要的朋友可以参考下
    2015-02-02
  • Java设计模式之访问者模式

    Java设计模式之访问者模式

    这篇文章介绍了Java设计模式之访问者模式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-10-10
  • spring scheduled单线程和多线程使用过程中的大坑

    spring scheduled单线程和多线程使用过程中的大坑

    本文主要介绍了spring scheduled单线程和多线程使用过程中的大坑,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Java 9中的"菱形"语法详解

    Java 9中的"菱形"语法详解

    Java 9 再次增强了“菱形”语法,它甚至允许在创建匿名内部类时使用菱形语法,Java 可根据上下文来推断匿名内部类中泛型的类型,下面程序示范了在匿名内部类中使用菱形语法,感兴趣的朋友跟随小编一起看看吧
    2023-06-06
  • 详解RestTemplate 用法

    详解RestTemplate 用法

    RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,也有的称之为网络框架,说白了就是Java版本的一个postman,这篇文章主要介绍了详解RestTemplate 用法,需要的朋友可以参考下
    2022-07-07

最新评论