什么是跨域问题?相信很多做过前后端分离项目的朋友都了解。由于浏览器同源策略的限制,Ajax请求请求到非同源的后端服务器时,会报跨域问题的错误。如下:
解决跨域问题一般有三种方式:
利用 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。JSONP 只支持 GET 请求,存在一定的缺陷,本文不展开讨论。
Nginx解决跨域请求的原理是绕过同源策略,请求的是与前端同源的服务器地址,使用Nginx反向代理到真正的后端服务器。
nginx.conf的配置:
server {
listen 80;
server_name www.a.com;
# 匹配以/apis/开头的请求
location ^~ /apis/ {
proxy_pass http://www.b.com;
}
}
这样配置,http://ww.a.com/apis/login 的请求实际会转发到 http://ww.b.com/apis/login 处理
nginx.conf 的 配置:
server {
listen 80;
server_name www.a.com;
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
root /usr/share/nginx/wwwroot/cdn;
index index.jsp index.html index.htm;
}
}
CORS 是一个 W3C 标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出 XMLHttpRequest 请求,从而克服了 AJAX 只能同源使用的限制。
CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。
@CrossOrigin(origins = "*", maxAge = 3600)
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 跨域配置
* @author maihaixian
* @date 2019/10/15
*/
@Configuration
public class CORSConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(false).maxAge(3600);
}
}
对于非简单请求的跨源请求,浏览器会在真实请求发出前,增加一次OPTION请求,称为预检请求(preflight request)。预检请求将真实请求的信息,包括请求方法、自定义头字段、源信息添加到 HTTP 头信息字段中,询问服务器是否允许这样的操作。
然而我们的安全框架使用的是Spring Security OAuth2,访问api时,会先发起OPTION的请求,但是该请求会直接被security 拦截,因为options请求没有携带token,所以直接返回401,就不会在发起get或post请求了。
所以要新增spring security配置,放行OPTIONS请求:.
antMatchers(HttpMethod.OPTIONS).permitAll()
整个SecurityConfig配置文件:
import com.marvin.demo.spring.cloud.gw.handler.SecurityAuthenticationEntryPoint;
import com.marvin.demo.spring.cloud.gw.properties.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
/**
* 资源服务器安全配置
* @Description:
* @Author Marvin
* @Date 2019-05-27 16:46
*/
@EnableResourceServer
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
public class ResourceSecurityConfig extends ResourceServerConfigurerAdapter {
@Autowired
private SecurityProperties securityProperties;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// 配置不需要验证的路径
.antMatchers(securityProperties.getIgnore().getHttpUrls()).permitAll()
//放行options请求,解决跨域问题首次请求options,第二次才是真实请求
.antMatchers(HttpMethod.OPTIONS).permitAll()
//任何请求都需要身份认证
.anyRequest().authenticated()
.and()
//禁用CSRF
.csrf().disable()
// 用来解决匿名用户访问无权限资源时的异常
.exceptionHandling().authenticationEntryPoint(new SecurityAuthenticationEntryPoint());
}
}