Spring Security使用中Preflight请求和跨域问题详解

Spring Security

Spring Security是能够为J2EE项目提供综合性的安全访问控制解决方案的安全框架。它依赖于Servlet过滤器。这些过滤器拦截进入请求,并且在应用程序处理该请求之前进行某些安全处理。

Spring Security对用户请求的拦截过程如下:

背景

在一个前后端分离开发的项目中,使用SpringSecurity做安全框架,用JWT来实现权限管理提升RESTful Api的安全性。首先遇到的就是跨域问题,但是在携带jwt请求过程中出现了服务端获取不到jwt情况。

跨域问题

在开发过程中遇到CORS (跨域资源共享) 的问题,简单的在服务器端设置了允许跨域访问,但是在携带jwt请求过程中出现

因为jwt是放在request header中,忽略了在跨域处理是加上允许自己定于的header字段

@Component
public class CorsFilter implements Filter {

 Logger logger= LoggerFactory.getLogger(CorsFilter.class);

 @Override
 public void init(FilterConfig filterConfig) throws ServletException {

 }

 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  HttpServletRequest request= (HttpServletRequest) servletRequest;
  HttpServletResponse response= (HttpServletResponse) servletResponse;
  response.setHeader("Access-Control-Allow-Origin",request.getHeader("origin"));
  response.setHeader("Access-Control-Allow-Origin","*"); //允许跨域访问的域
  response.setHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS,DELETE,PUT"); //允许使用的请求方法
  response.setHeader("Access-Control-Expose-Headers","*");
  response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Cache-Control,Pragma,Content-Type,Authorization"); //允许使用的请求方法
  response.setHeader("Access-Control-Allow-Credentials","true");//是否允许请求带有验证信息
  filterChain.doFilter(servletRequest, servletResponse);
 }

 @Override
 public void destroy() {

 }
}

在网上搜索提到要对OPTIONS请求进行处理返回200,但是测试并没有起到效果

这里的OPTIONS请求实际上就是preflight请求

Preflight请求

但是问题依然没有解决,出现如下

google了之后才知道preflight 请求的相关信息

在我们调用后台接口的时候,经常会发现请求了两次,其实第一次发送的就是preflight request(预检请求)。

为什么需要preflight request

我们都知道浏览器的同源策略,就是出于安全考虑,浏览器会限制从脚本发起的跨域HTTP请求,像XMLHttpRequest和Fetch都遵循同源策略。

浏览器限制跨域请求一般有两种方式:

浏览器限制发起跨域请求 跨域请求可以正常发起,但是返回的结果被浏览器拦截了

一般浏览器都是第二种方式限制跨域请求,那就是说请求已到达服务器,并有可能对数据库里的数据进行了操作,但是返回的结果被浏览器拦截了,那么我们就获取不到返回结果,这是一次失败的请求,但是可能对数据库里的数据产生了影响。

为了防止这种情况的发生,规范要求,对这种可能对服务器数据产生副作用的HTTP请求方法,浏览器必须先使用OPTIONS方法发起一个预检请求,从而获知服务器是否允许该跨域请求:如果允许,就发送带数据的真实请求;如果不允许,则阻止发送带数据的真实请求。

浏览器将CORS请求分成两类:简单请求和非简单请求。

简单请求

1.请求方法是以下三种方法之一

  • HEAD
  • GET
  • POST

2.HTTP的头信息不超出以下几种字段

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不同时满足上面两个条件,就属于非简单请求。

而浏览器对这两种请求的处理是不一样的。

非简单请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)

与cors相关更详细的看参考底部链接

解决方法

在我们后台用了Spring Security作为安全框架,并且没有对Preflight这个请求做出相应的处理,那么这个请求会导致权限管控失败。

处理起来也很简单,只需要在spring security配置类configure方法中增加放行preflight请求

 @Override
 protected void configure(HttpSecurity http) throws Exception {
  http
    // 由于使用的是JWT,我们这里不需要csrf
    .csrf().disable()
    // 基于token,所以不需要session
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
    .authorizeRequests()
    // 所有 / 的所有请求 都放行
    .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() //对preflight放行
    .antMatchers("/*").permitAll()
    .antMatchers("/u").denyAll()
    .antMatchers("/article/**").permitAll()
    .antMatchers("/video/**").permitAll()
    .antMatchers("/api/**").permitAll()
    .antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**","/swagger-ui.html", "/webjars/**")
    .permitAll()
    .antMatchers("/manage/**").hasRole("ADMIN") // 需要相应的角色才能访问
    // 除上面外的所有请求全部需要鉴权认证
    .anyRequest().authenticated();

  // 禁用缓存
  http.headers().cacheControl();
  // 添加JWT filter
  http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
  //添加未授权处理
  http.exceptionHandling().authenticationEntryPoint(getAuthenticationEntryPoint());
  //权限不足处理
  http.exceptionHandling().accessDeniedHandler(getAccessDeniedHandler());

 }

最终问题得到解决!

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

参考:

前端 | 浅谈preflight request
跨域资源共享 CORS 详解

(0)

相关推荐

  • Spring Boot中整合Spring Security并自定义验证代码实例

    最终效果 1.实现页面访问权限限制 2.用户角色区分,并按照角色区分页面权限 3.实现在数据库中存储用户信息以及角色信息 4.自定义验证代码 效果如下: 1.免验证页面 2.登陆页面 在用户未登录时,访问任意有权限要求的页面都会自动跳转到登陆页面. 3.需登陆才能查看的页面 用户登陆后,可以正常访问页面资源,同时可以正确显示用户登录名: 4.用户有角色区分,可以指定部分页面只允许有相应用户角色的人使用 4.1.只有ADMIN觉得用户才能查看的页面(权限不足) 4.2.只有ADMIN觉得用户才能查

  • java中Spring Security的实例详解

    java中Spring Security的实例详解 spring security是一个多方面的安全认证框架,提供了基于JavaEE规范的完整的安全认证解决方案.并且可以很好与目前主流的认证框架(如CAS,中央授权系统)集成.使用spring security的初衷是解决不同用户登录不同应用程序的权限问题,说到权限包括两部分:认证和授权.认证是告诉系统你是谁,授权是指知道你是谁后是否有权限访问系统(授权后一般会在服务端创建一个token,之后用这个token进行后续行为的交互). spring

  • Spring security实现权限管理示例

    Spring security实现权限管理示例,具体如下: 1.配置文件 1.POM.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.o

  • Java中SpringSecurity密码错误5次锁定用户的实现方法

    Spring Security简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作. 下面看下实例代码: 第

  • java中自定义Spring Security权限控制管理示例(实战篇)

    背景描述 项目中需要做细粒的权限控制,细微至url + httpmethod (满足restful,例如: https://.../xxx/users/1, 某些角色只能查看(HTTP GET), 而无权进行增改删(POST, PUT, DELETE)). 表设计 为避嫌,只列出要用到的关键字段,其余敬请自行脑补. 1.admin_user 管理员用户表, 关键字段( id, role_id ). 2.t_role 角色表, 关键字段( id, privilege_id ). 3.t_privi

  • 话说Spring Security权限管理(源码详解)

    最近项目需要用到Spring Security的权限控制,故花了点时间简单的去看了一下其权限控制相关的源码(版本为4.2). AccessDecisionManager spring security是通过AccessDecisionManager进行授权管理的,先来张官方图镇楼. AccessDecisionManager AccessDecisionManager 接口定义了如下方法: //调用AccessDecisionVoter进行投票(关键方法) void decide(Authent

  • Spring security实现登陆和权限角色控制

     随笔简介 1.spring版本:4.3.2.RELEASE+spring security 版本:4.1.2.RELEASE(其它不做说明) 2.所展示内容全部用注解配置 3.springmvc已经配置好,不作说明 4.会涉及到springmvc,spel,el的东西,不熟悉的同学可以先去看一下这方面内容,特别是springmvc 首先想一下,登陆需要什么,最简单的情况下,用户名,密码,然后比对数据库,如果吻合就跳转到个人页面,否则回到登陆页面,并且提示用户名密码错误.这个过程中应该还带有权限

  • Spring Security使用中Preflight请求和跨域问题详解

    Spring Security Spring Security是能够为J2EE项目提供综合性的安全访问控制解决方案的安全框架.它依赖于Servlet过滤器.这些过滤器拦截进入请求,并且在应用程序处理该请求之前进行某些安全处理. Spring Security对用户请求的拦截过程如下: 背景 在一个前后端分离开发的项目中,使用SpringSecurity做安全框架,用JWT来实现权限管理提升RESTful Api的安全性.首先遇到的就是跨域问题,但是在携带jwt请求过程中出现了服务端获取不到jwt

  • 使用Spring CROS解决项目中的跨域问题详解

    CROS(Cross-Origin Resource Sharing) 用于解决浏览器中跨域请求的问题.简单的Get请求可以使用JSONP来解决,而对于其它复杂的请求则需要后端应用的支持CROS.Spring在4.2版本之后提供了@CrossOrigin 注解来实现对Cross的支持. 在Controller方法上配置 @CrossOrigin(origins = {"http://loaclhost:8088"}) @RequestMapping(value = "/cro

  • Vue axios与Go Frame后端框架的Options请求跨域问题详解

    跨域问题可从前后两端分开排查: 前端:Vue + axios axios 请求头使用 'Content-Type': 'application/json', 并且在Header中设置了 Authorization 字段用于传递 Token, 参数未经 Qs 转码, 使用以下代码测试登录接口: // 为方便操作,已将 axios 实例挂载到 this.$axios 上 this.$axios.post('/signin', {account: '', password: ''}) .then(re

  • Ajax解决跨域之设置CORS响应头实现跨域案例详解

    1.设置CORS响应头实现跨域 跨源资源共享(CORS) 1.1 什么是CORS CORS(Cross-Origin Resource Sharing),跨域资源共享.CORS 是官方的跨域解决方 案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求.跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些 源站通过浏览器有权限访问哪些资源 1.2 CORS 怎么工作的? CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览

  • Spring Security 实现用户名密码登录流程源码详解

    目录 引言 探究 登录流程 校验 用户信息保存 引言 你在服务端的安全管理使用了 Spring Security,用户登录成功之后,Spring Security 帮你把用户信息保存在 Session 里,但是具体保存在哪里,要是不深究你可能就不知道, 这带来了一个问题,如果用户在前端操作修改了当前用户信息,在不重新登录的情况下,如何获取到最新的用户信息? 探究 无处不在的 Authentication 玩过 Spring Security 的小伙伴都知道,在 Spring Security 中

  • 前端跨域问题解决及七大跨域原理详解

    目录 为什么跨域? 跨域的时机? 同域情况 && 跨域情况? 解决跨域的方案 JSONP WebSocket Cors Node接口代理 Nginx postMessage document.domain && iframe 咱们做前端的,平时跟后端对接接口那是必须的事情,但是可能很多同学忽略了一个对接过程中可能会发生的问题——跨域,那跨域到底是啥呢?为什么会跨域呢?又怎么才能解决呢? 为什么跨域? 为什么会出现跨域问题呢?那就不得不讲浏览器的同源策略了,它规定了协议号-域

  • Vue如何解决跨域问题详解

    什么是跨域 跨域指浏览器不允许当前页面的所在的源去请求另一个源的数据.源指协议,端口,域名.只要这个3个中有一个不同就是跨域. 这里列举一个经典的列子: #协议跨域http://a.baidu.com访问https://a.baidu.com:#端口跨域http://a.baidu.com:8080访问http://a.baidu.com:80:#域名跨域http://a.baidu.com访问http://b.baidu.com: 通常在不同服务器访问过程中可能会遇到跨域问题,也就是口头上常说

  • vue使用代理解决请求跨域问题详解

    在日常开发中,我们前端必不可少的需要像后端请求数据. 但是一般前后端分离,所以域名.端口等肯定不尽相同,这样就不可避免的会遇到浏览器的同源策略限制. 在一般情况下,后端都会设置请求跨域允许的来源.方法等. 但是也保不准后端疏忽而忘记这个问题. 那为了不影响我们的开发,前端只能被动的去找后端解决跨域问题. 其实,我们前端也可以解决跨域问题,那就是使用代理. 举个例子: 我请求的地址是这个:http://192.168.12.36:9000/api/SourceManager 但是我本地的vue项目

  • AJAX请求以及解决跨域问题详解

    目录 AJAX 介绍 一.原生AJAX请求(GET) 二.jQuery AJAX请求(GET 和POST) 三.跨域问题的解决 四.其他解决跨域问题方法 总结 AJAX 介绍 AJAX其实就是异步的js和xml 通过ajax可以在浏览器中发送异步请求. 最大优势:无刷新获取数据 优点: 1.可以无需刷新页面与服务器进行通信 2.允许根据用户事件更新部分页面内容 当然也存在其缺点问题:比如跨域问题等! 一.原生AJAX请求(GET) 由于get和post请求类似,原生代码相比jQuery复杂一些:

  • 如何使用Nginx解决跨域问题详解

    目录 先来说一下什么是同源策略 什么是跨域? 跨域分类 Nginx解决跨域问题 解释 1.Access-Control-Allow-Origin 2.Access-Control-Allow-Headers 是为了防止出现以下错误: 3.Access-Control-Allow-Methods 是为了防止出现以下错误: 4.给OPTIONS 添加 204的返回,是为了处理在发送POST请求时Nginx依然拒绝访问的错误 预检请求(preflight request) 尾声 先来说一下什么是同源策

随机推荐