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

}

}

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

以上是 Security框架:如何使用CorsFilter解决前端跨域请求问题 的全部内容, 来源链接: utcz.com/p/250743.html

回到顶部