欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringBoot框架实现跨域访问学习

程序员文章站 2022-05-04 16:22:50
...

引言:

最近有时间,就找了点资料,把工作中用到的SpringBoot配置跨域CORS访问仔细研究一下:

在Java 编程中,web项目还是经常遇到一些跨域的使用。这里主要记录几种spring框架,spring boot中的一些常见的几种配置跨域的方法。

    CORS(Cross-origin resource sharing-跨源资源共享)允许网页从其他域向浏览器请求额外的资源,例如 字体,CSS或来自CDN的静态图像。 CORS有助于将来自多个域的网页内容提供给通常具有相同安全策略的浏览器。 在这个例子中,我们将学习如何在Spring MVC应用程序的方法和全局级别启用CORS支持。

 

一.spring框架中使用@CrossOrigin注解方法级CORS

 

Spring MVC提供了@CrossOrigin注解。 这个注释标注了注释的方法或类型,允许跨源请求。

    默认情况下,@CrossOrigin允许所有的来源,所有的头文件,@RequestMapping注解中指定的HTTP方法和30分钟的maxAge。 您可以覆盖这些赋予注释属性值的设置:
 

属性 说明
origins 允许的来源列表. 他的值放置在HTTP协议的响应header的Access-Control-Allow-Origin .
– – 意味着所有的源都是被允许的。
– 如果未定义,则允许所有来源。
allowedHeaders 实际请求期间可以使用的请求标头列表. 值用于预检的响应header Access-Control-Allow-Headers。
– – 意味着允许客户端请求的所有头文件。
– 如果未定义,则允许所有请求的headers。
methods 支持的HTTP请求方法列表。 如果未定义,则使用由RequestMapping注释定义的方法。
exposedHeaders 浏览器允许客户端访问的响应头列表。 在实际响应报头Access-Control-Expose-Headers中设置值。
– 如果未定义,则使用空的暴露标题列表。
allowCredentials 它确定浏览器是否应该包含与请求相关的任何cookie。
– false – cookies 不应该包括在内。
– "" (空字符串) – 意味着未定义.
– true – 预响应将包括值设置为true的报头Access-Control-Allow-Credentials。
– 如果未定义,则允许所有凭据。
maxAge 预响应的高速缓存持续时间的最大时间(以秒为单位)。 值在标题Access-Control-Max-Age中设置。
– 如果未定义, 最大时间设置为1800秒(30分钟).

aaa@qq.com Class/Controller Level

@CrossOrigin(origins = "*", allowedHeaders = "*")
@Controller
public class HomeController
{
    @GetMapping(path="/")
    public String homeInit(Model model) {
        return "home";
    }
}

aaa@qq.com at Method Level

@Controller
public class HomeController
{
    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @GetMapping(path="/")
    public String homeInit(Model model) {
        return "home";
    }
}

1.3 @CrossOrigin Overridden at Method Level

homeInit()方法只能从域http://example.com访问。 其他方法在HomeController中将可以从所有域访问。

@Controller
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class HomeController
{
    @CrossOrigin(origins = "http://example.com")
    @GetMapping(path="/")
    public String homeInit(Model model) {
        return "home";
    }
}

 

二.Spring框架全局CORS 配置

经过查了如下的几篇博客,个人目前觉得可以分四种实现方法:

2.1    直接使用Request和Response来实现CORS跨域配置:

public class CorsFilter extends OncePerRequestFilter {

    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");
    
        if (request.getMethod().equals("OPTIONS"))
            response.setStatus(HttpServletResponse.SC_OK);
        else 
            filterChain.doFilter(request, response);
    
    }
}
@Bean
public CorsFilter corsFilter() throws Exception {
    return new CorsFilter();
}

http
    .addFilterBefore(corsFilter(), UsernamePasswordAuthenticationFilter.class)
    .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
    .headers()
    .cacheControl();

2.2   不依赖spring-boot-starter-security包来实现CORS 的配置:

  @Bean
  CorsConfigurationSource corsConfigurationSource() {
      CorsConfiguration configuration = new CorsConfiguration();
      configuration.setAllowedOrigins(Arrays.asList("http://localhost:63342"));
      configuration.setAllowedMethods(Arrays.asList("GET","POST", "PUT", "DELETE"));
      // 如果所有的属性不全部配置,一定要执行该方法
      configuration.applyPermitDefaultValues();

      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
      source.registerCorsConfiguration("/**", configuration);
      return source;
  }

  @Bean
  CorsFilter corsFilter(CorsConfigurationSource corsConfigurationSource) {
      CorsFilter corsFilter = new CorsFilter(corsConfigurationSource);
      return corsFilter;
  }

2.3   依赖spring-boot-starter-security包来实现CORS 的Spring Security配置:

@SpringBootApplication
public class AuthorityManagementApplication extends WebSecurityConfigurerAdapter {
    public static void main(String[] args) {
        SpringApplication.run(AuthorityManagementApplication.class, args);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * CORS 必须在Security之前处理
         * 原因:这个 pre-flight 请求不会包含任何cookies,如果请求不包括任何cookies和Security先处理的话,那么这个请求会被拒绝
         * 官方地址:https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#cors
         * CORS must be processed before Spring Security because the pre-flight request will not contain any cookies (i.e. the JSESSIONID).
         * If the request does not contain any cookies and Spring Security is first,
         * the request will determine the user is not authenticated (since there are no cookies in the request) and reject it.
         */
        http.cors();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:63342"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST", "PUT", "DELETE"));
        // 如果所有的属性不全部配置,一定要执行该方法
        configuration.applyPermitDefaultValues();

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

2.4   Spring Boot CORS 使用WebMvcConfigurer配置:

这个我用一个可执行实例来介绍:

使用IDEA开发工具创建一个SpringBoot项目,预先添加Web依赖即可,项目结构如下图1所示:

SpringBoot框架实现跨域访问学习

图1

CORSConfiguration

我们只需要添加项目Web依赖就可以了,下面我们开始添加CORS的配置信息,我们创建一个CORSConfiguration配置类,如下图2所示:

 

SpringBoot框架实现跨域访问学习

图2

上图2内我们的CORSConfiguration配置类继承了WebMvcConfiugrationAdaper父类并且重写了addCorsMappings方法,我们来简单介绍下我们的配置信息

addMapping:配置可以被跨域的路径,可以任意配置,可以具体到直接请求路径。
allowedMethods:允许所有的请求方法访问该跨域资源服务器,如:POST、GET、PUT、DELETE等。
allowedOrigins:允许所有的请求域名访问我们的跨域资源,可以固定单条或者多条内容,如:"http://www.baidu.com",只有百度可以访问我们的跨域资源。
allowedHeaders:允许所有的请求header访问,可以自定义设置任意请求头信息,如:"X-YAUTH-TOKEN"

编写跨域资源请求

我们的跨域配置到目前来说已经配置完成了,SpringBoot已经为我们内置相关配置,我们只需要重写方法修改部分参数即可,下面我们来创建一个测试跨域资源的控制器,如下图3所示:

 

SpringBoot框架实现跨域访问学习

图3

在图3内的IndexController控制器内,我们仅仅添加了一个测试返回文本的内容,当然这个控制器可以处理任意业务逻辑。

测试跨域请求

我们在项目外创建一个index.html页面(上传码云后会在resources目录找到),页面内添加部分jquery代码,如下图4所示:

 

SpringBoot框架实现跨域访问学习

图4

我们引用了在线的jquery代码,并且在页面加载的时候为id=cors的输入按钮绑定点击事件,点击按钮时就会请求我们的/cors跨域资源路径,下面我们来运行项目测试下跨域请求,项目运行日志如下图5所示:

 

SpringBoot框架实现跨域访问学习

图5

可以看到上图5内项目启动时SpringBoot内置的SpringMVC已经把我们的/cors添加到映射集合,我们打开之前编写的index.html网页,界面效果如下图6所示:

 

SpringBoot框架实现跨域访问学习

图6

接下来我们点击“CORS跨域测试”按钮,查看下效果,如下图7所示:

 

SpringBoot框架实现跨域访问学习

图7

上图7内可以看到,界面给我返回了我们/cors路径返回的文本内容,证明我们的ajax请求完美的通过跨域资源库访问了开放跨域的资源路径。

下面我们来把我们的跨域配置注释掉,重启项目后刷新index.html再次点击“CORS跨域测试”按钮,界面输出效果如下图8所示:

 

SpringBoot框架实现跨域访问学习

图8

可以看到我们点击后并没有获取到返回内容,而是给我们提示了异常,告诉我们无法加载资源。

 

前几天学习了过滤器,有幸在查资料的过程中找到了一个过滤器和CORS跨域结合的代码样例,拿过来跟大家分享:

本文介绍了spring-boot 允许接口跨域并实现拦截(CORS),分享给大家,也给自己留个笔记

pom.xml(依赖的jar)

?

1

2

3

4

5

// 在spring-boot-starter-web的启动器中,已经依赖好了

<dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-web</artifactId>

</dependency>

CORS跨域的配置(主要配置允许什么样的方法跨域)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.cors.CorsConfiguration;

import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import org.springframework.web.filter.CorsFilter;

import org.springframework.web.servlet.config.annotation.CorsRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.util.ArrayList;

import java.util.List;

/**

 * Created by Msater Zg on 2017/4/3.

 */

@Configuration

public class CorsConfig extends WebMvcConfigurerAdapter {

  @Override

  public void addCorsMappings(CorsRegistry registry) {

    registry.addMapping("/**")

        .allowedOrigins("*")

        .allowCredentials(true)

        .allowedMethods("GET", "POST", "DELETE", "PUT")

        .maxAge(3600);

  }

  private CorsConfiguration buildConfig() {

    CorsConfiguration corsConfiguration = new CorsConfiguration();

    List<String> list = new ArrayList<>();

    list.add("*");

    corsConfiguration.setAllowedOrigins(list);

    /*

    // 请求常用的三种配置,*代表允许所有,当时你也可以自定义属性(比如header只能带什么,只能是post方式等等)

    */

    corsConfiguration.addAllowedOrigin("*");

    corsConfiguration.addAllowedHeader("*");

    corsConfiguration.addAllowedMethod("*");

    return corsConfiguration;

  }

  @Bean

  public CorsFilter corsFilter() {

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

    source.registerCorsConfiguration("/**", buildConfig());

    return new CorsFilter(source);

  }

}

拦截器配置(可以根据不同路径,配置不同的拦截器)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

/**

 * Created by Msater Zg on 2017/4/5.

 * 拦截器

 */

public class ApiInterceptor implements HandlerInterceptor {

  @Override

  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    // 请求前调用

    System.out.println("拦截了");

    return true;

  }

  @Override

  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    // 请求过程中调用

    System.out.println("拦截了");

  }

  @Override

  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    // 请求完成时调用

    System.out.println("拦截了");

  }

}

拦截器管理类,用于生成项目的拦截器链

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**

 * Created by Msater Zg on 2017/4/5.

 * 拦截器管理工具

 */

@Configuration

public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {

  @Override

  public void addInterceptors(InterceptorRegistry registry) {

    // 多个拦截器组成一个拦截器链

    // addPathPatterns 用于添加拦截规则

    // excludePathPatterns 用户排除拦截

    registry.addInterceptor(new ApiInterceptor()).addPathPatterns("/user/**"); //对来自/user/** 这个链接来的请求进行拦截

    super.addInterceptors(registry);

  }

}

 

本文我自己加了一些自己的理解,代码样例是参考如下博客链接:

https://www.jb51.net/article/121548.htm

https://segmentfault.com/a/1190000012364985?utm_source=tag-newest

https://www.cnblogs.com/shihaiming/p/8716830.html

https://blog.csdn.net/ACMer_AK/article/details/78960164

http://www.leftso.com/blog/303