Spring Security系列教程25--解决Spring Security环境中的跨域问题

简介: 前言上一章节中,一一哥 给各位讲解了同源策略和跨域问题,以及跨域问题的解决方案,在本篇文章中,我会带大家进行代码实现,看看在Spring Security环境中如何解决跨域问题。一. 启用Spring Security 的CORS支持1. 创建web接口我先在SpringBoot环境中,创建一个端口号为8080的web项目,注意这个web项目没有引入Spring Security的依赖包。然后在其中创建一个IndexController,定义两个测试接口以便被ajax进行跨域访问。@RestControllerpublic class IndexController {

前言

上一章节中,一一哥 给各位讲解了同源策略和跨域问题,以及跨域问题的解决方案,在本篇文章中,我会带大家进行代码实现,看看在Spring Security环境中如何解决跨域问题。

一. 启用Spring Security 的CORS支持

1. 创建web接口

我先在SpringBoot环境中,创建一个端口号为8080的web项目,注意这个web项目没有引入Spring Security的依赖包。然后在其中创建一个IndexController,定义两个测试接口以便被ajax进行跨域访问。

@RestControllerpublicclassIndexController {
@GetMapping("/hello")
publicStringhello() {
return"get hello";
    }
@PostMapping("/hello")
publicStringhello2() {
return"post hello";
    }
}

8080项目的代码结构:

请参考如下代码结构进行项目创建。

2. 执行ajax请求

我们接下来再创建另一个端口号为8082的web项目,注意这个web项目也没有引入Spring Security的依赖包。接着在这里定义一个index.html页面,利用ajax跨域访问8080项目中的web接口。

<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><title>Index</title><scripttype="text/javascript"src="jquery-2.1.0.js"></script></head><body><divid="app"></div><inputtype="button"onclick="btnClick()"value="get请求"><inputtype="button"onclick="btnClick2()"value="post请求"><script>functionbtnClick() {
$.get('http://localhost:8080/hello', function (msg) {
$("#app").html(msg);
        });
    }
functionbtnClick2() {
$.post('http://localhost:8080/hello', function (msg) {
$("#app").html(msg);
        });
    }
</script></body></html>

8082项目的代码结构:

请参考如下代码结构进行项目创建。

3. 发起跨域请求

我们访问8082项目中的index.html页面,然后分别执行get与post请求,这时候就可以在浏览器的控制台上看到产生了CORS跨域问题,出现了CORS error状态,在请求头中出现了Referer Policy: strict-origin-when-cross-origin。

4. 解决跨域问题

既然现在产生了跨域问题,那么该怎么解决呢?其实我们可以采用如下两种方式之一来解决跨域问题。

方式1:在接口方法上利用@CrossOrigin注解解决跨域问题

@RestControllerpublicclassIndexController {
@CrossOrigin(value="http://localhost:8082")
@GetMapping("/hello")
publicStringhello() {
return"get hello";
    }
@CrossOrigin(value="http://localhost:8082")
@PostMapping("/hello")
publicStringhello2() {
return"post hello";
    }
}

方式2:通过实现WebMvcConfigurer接口来解决跨域问题

@ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer {
@OverridepublicvoidaddCorsMappings(CorsRegistryregistry) {
registry.addMapping("/**")
                .allowedOrigins("http://localhost:8082")
                .allowedMethods("*")
                .allowedHeaders("*");
    }
}

当进行了跨域设置之后,我们再次进行跨域请求,就可以看到请求成功了。

二. Spring Security环境下的跨域问题解决

1. 引入Spring Security依赖

通过上面的配置,我们已经解决了Ajax的跨域请求问题,但是这个案例中也有潜在的威胁存在,常见的就是 CSRF(Cross-site request forgery) 跨站请求伪造。跨站请求伪造也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF,是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。

所以为了提高网站的安全性,我在上面Spring Boot项目的基础之上,添加Spring Security的依赖包,但是暂时不进行任何别的操作。

 

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency></dependencies>

2. 重启8080项目进行测试

接着我就重启8080这个Spring Boot项目,然后在8082项目中再次进行跨域请求,我们会发现在引入Spring Security后,再次产生了跨域问题。

3. 解决Spring Security环境下跨域问题的3种方案

通过实验可知,如果使用了 Spring Security,上面的跨域配置会失效,因为请求会被 Spring Security 拦截。那么在Spring Security环境中,如何解决跨域问题呢?这里我们有3种方式可以开启 Spring Security 对跨域的支持。

3.1 方式一:开启cors方法

我们在上面的案例之上,编写一个SecurityConfig配置类,在configure方法中,利用cors() 开启Spring Security 对 CORS 的支持:

@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter {
@Overrideprotectedvoidconfigure(HttpSecurityhttp) throwsException {
http.authorizeRequests()
                .anyRequest()
                .permitAll()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .httpBasic()
                .and()
//支持跨域访问                .cors()
                .and()
                .csrf()
                .disable();
    }
}

3.2 方式二:进行全局配置

第二种方式是去除上面的跨域配置,直接在 Spring Security 中做全局配置,如下:

@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter {
@Overrideprotectedvoidconfigure(HttpSecurityhttp) throwsException {
http.authorizeRequests()
                .anyRequest()
                .permitAll()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .httpBasic()
                .and()
//支持跨域访问                .cors()
                .configurationSource(corsConfigurationSource())
                .and()
                .csrf()
                .disable();
    }
@BeanpublicCorsConfigurationSourcecorsConfigurationSource() {
UrlBasedCorsConfigurationSourcesource=newUrlBasedCorsConfigurationSource();
CorsConfigurationconfiguration=newCorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
configuration.setMaxAge(Duration.ofHours(1));
source.registerCorsConfiguration("/**", configuration);
returnsource;
    }
}

以上2个方法,都可以实现在Spring Security环境下的跨域访问。

3.3 方式三:支持OAuth2的跨域访问

我们开发时,还有一种情况就是支持 OAuth2 相关接口的跨域,比如用户要访问 OAuth2 中的 /oauth/token 等接口。我们可以配置一个全局的 CorsFilter 跨域过滤器类,核心代码如下:

/*** 跨域配置方式3:定义全局跨域过滤器**/@ConfigurationpublicclassGlobalCorsConfiguration {
@BeanpublicCorsFiltercorsFilter() {
CorsConfigurationcorsConfiguration=newCorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
UrlBasedCorsConfigurationSourceurlBasedCorsConfigurationSource=newUrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
returnnewCorsFilter(urlBasedCorsConfigurationSource);
    }
}
@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter {
@Overrideprotectedvoidconfigure(HttpSecurityhttp) throwsException {
//跨域方式3:http.requestMatchers()
                .antMatchers(HttpMethod.OPTIONS, "/oauth/**")
                .and()
                .csrf()
                .disable()
                .formLogin()
                .and()
                .cors();
    }
}

该方式也可以实现Spring Security中的跨域访问。

4. 代码结构

以下是本案例的代码结构,可以参考下图进行项目创建:

至此,我就带各位解决了Spring Security环境中的跨域问题,你学会了吗?

相关文章
|
2月前
|
Cloud Native Java 对象存储
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
展望未来,随着5G、边缘计算等新技术的兴起,微服务架构的设计理念将会更加深入人心,Spring Cloud和Netflix OSS也将继续引领技术潮流,为企业带来更为高效、灵活且强大的解决方案。无论是对于初创公司还是大型企业而言,掌握这些前沿技术都将是在激烈市场竞争中脱颖而出的关键所在。
58 0
|
12天前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
25 2
|
2月前
|
XML JavaScript Java
Spring Retry 教程
Spring Retry 是 Spring 提供的用于处理方法重试的库,通过 AOP 提供声明式重试机制,不侵入业务逻辑代码。主要步骤包括:添加依赖、启用重试机制、设置重试策略(如异常类型、重试次数、延迟策略等),并可定义重试失败后的回调方法。适用于因瞬时故障导致的操作失败场景。
Spring Retry 教程
|
1月前
|
Cloud Native Java 对象存储
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
42 1
|
1月前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
详细介绍实现Java Spring Boot FCM推送教程
74 0
|
3月前
|
SQL Java 数据库连接
Spring Boot联手MyBatis,打造开发利器:从入门到精通,实战教程带你飞越编程高峰!
【8月更文挑战第29天】Spring Boot与MyBatis分别是Java快速开发和持久层框架的优秀代表。本文通过整合Spring Boot与MyBatis,展示了如何在项目中添加相关依赖、配置数据源及MyBatis,并通过实战示例介绍了实体类、Mapper接口及Controller的创建过程。通过本文,你将学会如何利用这两款工具提高开发效率,实现数据的增删查改等复杂操作,为实际项目开发提供有力支持。
137 0
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
24天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
125 2
|
3月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
24天前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
39 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块