关于springboot集成shiro后遇到的CORS跨域问题

关于带Cookie的跨域问题导致Shiro授权和认证失败的问题 问题描述:后端框架为SpringBoot,安全框架为Shiro。其中认证和授权都已经做好了,授权和认证主要是用注解的方式,主要采用了@RequiresAuthentication这个注解,意思是加上这个注解的方法,必须经过授权才可以访问,也就是必须登陆才可以。之后整个项目只用了Postman进行测试。 主要测试就是两方面,在不登陆的情况下去访问带有@RequiresAuthentication的... 阅读详情

废话不多说,先上解决办法,后边再说原理:

自定义MyFormAuthenticationFilter

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
    /**
     * 在访问controller前判断是否登录,返回json,不进行重定向。
     * @param request
     * @param response
     * @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        if (isAjax(request)) {
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json");
            //解决一下跨域问题
            httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
            httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
            httpServletResponse.setHeader("Access-Control-Max-Age", "0");
            httpServletResponse.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,userId,token");
            httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpServletResponse.setHeader("XDomainRequestAllowed","1");
            httpServletResponse.getWriter().write(BaseRestfulResult.needLogin().toJsonString());
            httpServletResponse.getWriter().flush();
            httpServletResponse.getWriter().close();
        } else {
            //saveRequestAndRedirectToLogin(request, response);
            /**
             * @Mark 非ajax请求重定向为登录页面
             */
            httpServletResponse.sendRedirect("/login");
        }
        return false;
    }

	//解决OPTIONS请求跨域问题
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (request instanceof HttpServletRequest) {
            if (((HttpServletRequest) request).getMethod().toUpperCase().equals("OPTIONS")) {
                return true;
            }
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }


    private boolean isAjax(ServletRequest request){
        String header = ((HttpServletRequest) request).getHeader("X-Requested-With");
        if("XMLHttpRequest".equalsIgnoreCase(header)){
            return Boolean.TRUE;
       }
       return Boolean.FALSE;
        return true;
    }
}

注意上边的isAccessAllowed()方法和onAccessDenied()方法中的几行httpServletResponse.setHeader(“xx”, “xxx”);,这两个地方是关键。
最后别忘了在config类中注册一下
shiroFilterFactoryBean.getFilters().put(“authc”, new MyFormAuthenticationFilter());
大功告成~

以下是原理

最近在用springboot写前后端分离项目的时候, 用postman测试接口没问题,但丢给前端测试的时候返回了跨域问题:
在这里插入图片描述
这就很奇怪,所有的controller上我都加了@CrossOrigin注解,为什么还会有跨域问题呢?

这里有个需要注意的地方: xx has been blocked by CORS policy
这个CORS是个什么东西呢?简单说是一种资源共享机制。当浏览器发起ajax请求的时候,会先发起一个method为OPTIONS的请求, 这个请求我们可以简单理解为一个探路请求, 该请求不携带信息, 只是为了测试一下目标服务器是否支持跨域,如果支持跨域的话,再发出后续的请求。
在这里插入图片描述
通过chrome控制台可以看出, 当我们尝试调用listByAdmin接口的时候,发出了一个OPTIONS请求,该请求返回200后,浏览器又发起了一个一模一样的请求,后边这个请求才是真正的请求,当然这是正常的情况。
问题就出在这个OPTIONS请求上, 因为我的项目是完全前后端分离的,前端请求的时候会在http header上携带token,后端利用token鉴权。然而OPTIONS请求(‘OPTIONS请求’这个叫法可能不准确,各位理解我说的是啥就行)默认是不携带token信息的,后端没有收到token,导致鉴权失败。

但是鉴权失败为什么报鉴权问题,反而报了个跨域问题呢?
先看一下一开始我是怎么处理鉴权失败的

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
   @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        if (isAjax(request)) {
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json");
            //返回给前端鉴权失败的信息
            httpServletResponse.getWriter().write(BaseRestfulResult.needLogin().toJsonString());	
            httpServletResponse.getWriter().flush();
            httpServletResponse.getWriter().close();
        } else {
            //saveRequestAndRedirectToLogin(request, response);
            /**
             * @Mark 非ajax请求重定向为登录页面
             */
            httpServletResponse.sendRedirect("/login");
        }
        return false;
    }
    }

首先判断是否ajax请求,如果是的话,将鉴权失败的信息返回给前端。 这个地方没有设置允许跨域的header,所以前端就出现了跨域问题。

解决之后的源码:

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        if (isAjax(request)) {
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json");
            //解决一下跨域问题
            httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
            httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
            httpServletResponse.setHeader("Access-Control-Max-Age", "0");
            httpServletResponse.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,userId,token");
            httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpServletResponse.setHeader("XDomainRequestAllowed","1");
            httpServletResponse.getWriter().write(BaseRestfulResult.needLogin().toJsonString());
            httpServletResponse.getWriter().flush();
            httpServletResponse.getWriter().close();
        } else {
            //saveRequestAndRedirectToLogin(request, response);
            /**
             * @Mark 非ajax请求重定向为登录页面
             */
            httpServletResponse.sendRedirect("/login");
        }
        return false;
    }

当然,最佳的解决方案是针对OPTIONS请求单独处理以下

   @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (request instanceof HttpServletRequest) {
            if (((HttpServletRequest) request).getMethod().toUpperCase().equals("OPTIONS")) {
                return true;
            }
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }
Zuul,Shiro跨域CORS请求踩坑实录 前言:前后端分离,业务分离,网关路由等已经成为当下web application开发的流行趋势。前端以单页面路由为核心的框架为主体,可以单独部署在nodejs或nginx上。后端以springboot为代表的分布式微服务框架为主体,可以独立运行在任何端口上。相互通过符合restful规范的接口访问或数据交换。在这样的开发模式下,首先需要解决的就是由于跨域而引起的访问,cookie传递以及权限... 阅读详情

相关推荐

sendRedirect()和forward()

sendRedirect()和forward()的区别,我是个新手,觉得很受用,呵呵,大家学习

springboot(shiro)+vue(axios)跨域问题记录

1. 通用设置 一旦前后端分离,就涉及到跨域问题(域名、端口、协议(http或https等)其一不一样就是跨域)。 在涉及到跨域问题时,浏览器发送请求前,会优先发送一个OPTION请求。 所以,对于springboot项目,只需要自定义一下web过滤器即可。 /** * 解决跨域问题 */ @Configuration public class WebConfig extends WebMvc...

王小禾 1496

java解决请求跨域的两种方法

主要为大家详细介绍了java解决请求跨域的两种方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

跨域请求

最近项目用到跨域登录请求并跳转,其实实际上用到的就是重定向和转发。 本来的基础知识,现在感觉很陌生,实现了功能,也加深了重定向和转发的理解。 javaweb实现跳转在前端和后端都可以实现。 前端使用window.location=url 后端使用response.senRedirect ,request.getRequestDispatcher().forward()。 重定向 response.senRedirect 属于重定向,不仅可以重定向到当前应用程序中的其他资源,还可以重定向到同一个站点上的其

小李的专栏 1349

coze+飞书多维表格,批量分析小红书笔记,关键还能获取图片(附保姆级教程)

通过coze工作流,一键同步小红书账号和笔记链接到飞书多维表格,效率飞升~

qq_24403067的博客 4175

CST仿真实例001:圆极化平板天线仿真

CST仿真实例001:圆极化平板天线仿真实例

weixin_47638568的博客 1万+

用ajax请求,在后台使用Response.sendRedirect(“XXX”)重定向无效

问题: 今天发现,当使用Ajax请求时,如果后台进行重定向到其他页面时是无法成功的,只能在浏览器地址栏输入才能够实现重定向。 原因: Ajax默认就是不支持重定向的,它是局部刷新,不重新加载页面。 ...

Lemon_MY的博客 2958

centos 添加新硬盘,对根目录扩容

本地安装了虚拟机,系统为centos7,使用过程中,渐渐地发现磁盘容量不够用了,于是在虚拟机中新增了一块硬盘。 进入系统内查看: sdb是新增的硬盘,大小为40g。 接下来有两种方式,一种是普通方式直接挂载。https://blog.youkuaiyun.com/qq_39314099/article/details/106200322 这样的话只有在挂载点的目录下操作才能使用到这个新硬盘,不是很理想。 还有一种方式lvm,逻辑卷管理的方式。 LVM简单介绍: 它是 Linux 下对磁盘分区进行管

qq_39314099的博客 1万+

springboot+shiro跨域解决方案

1.springboot跨域解决 添加配置以下配置即可解决 @Configuration public class CorsConfig implements WebMvcConfigurer { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMa

技术交流,共同进步 1566

【技术实践指南】Python解析FactSet Revere供应链数据:构建企业级断裂与重构监测指标

本文提供了一份企业级Python实践指南,详细解析如何利用FactSet Revere供应链数据库,构建供应链断裂与重构监测指标。内容涵盖数据清洗、关系对筛选、时间序列处理及核心指标(断裂、恢复、转移)的工程化实现,旨在帮助数据工程师与分析师搭建自动化、可解释的供应链风险监控系统。

weixin_29051811的博客 934

ETAS工具导入Com Arxml修改步骤

通讯协议栈开发一般通过导入DBC实现,ETAS工具本身导入DBC也是生成arxml后执行cfggen,本文介绍直接导入客户提供的arxml文件,实现通讯协议栈的生成。通过Arxml导入相比于DBC来说,少了从DBC转为arxml的过程。而且arxml中能提供的信息也会更多。如果是DBC的话,很多信息(如PNC的映射,CANTP的配置等)都需要额外配置。不过还有连DBC都无法提供的,那就更麻烦了~

赞的博客 1541

springboot集成shiro的权限中cors跨域问题

@Configurationpublic class CorsConfig { private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigi...

ditu5808的博客 454

《Python Web项目集锦》-专栏介绍和目录

本专栏专注于Python Web项目,涉及内容包含FastAPI、Django、Flask等,所有项目代码完整且可直接运行。不管是零基础还是有经验的开发,相信都能从本专栏获益。有任何问题欢迎私聊博主,专栏持续更新中...

数据知道的博客 5214

Springboot + Vue + shiro 实现前后端分离、权限控制

点击上方 阿拉奇学Java,选择 设为星标每天0点,干货准时奉上!作者:_Yufancnblogs.com/yfzhou/p/9813177.html本文总结自实习中对项目的重构。原先项...

qq_36189144的博客 226

【小白深度教程 1.8】手把手教你使用 Depth Anything V2 估计单目深度,并映射到 3D 点云(含 Python 代码)

我们尝试使用单目深度估计技术(Depth Anything V2),来进行准确的双目深度估计,并将场景转换成 3D 点云,Python 代码在最后。

2401_87064292的博客 5090

知识图谱(Knowledge Graph)原理与代码实战案例讲解

知识图谱(Knowledge Graph)原理与代码实战案例讲解 作者:禅与计算机程序设计艺术 / Zen and the Art of Computer Programming 1. 背景介绍 1.1 问题的由来

AI天才研究院 1078

Spring Boot + Vue + Shiro 实现前后端分离,写得太好了!

上一篇:一个90后员工猝死的全过程0、2T架构师学习资料干货分享作者:_Yufan来源:www.cnblogs.com/yfzhou/p/9813177.html本文总结自实习中对项目的重...

emprere的博客 547

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Spring Boot + Vue + Shiro 实现前后端分离、权限控制 (附源码)

点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐]原项目采用Springboot+freemarker模版,开发过程中觉得前端逻辑写的实在恶心,后端Controller层还必须返...

全栈开发者社区 598

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

SpringBoot面试题

概述 什么是 Spring Boot? Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。 Spring Boot 有哪些优点? Spring Boot 主要有如下优点: 容易上手,提升开发效率,为 Spring 开发提供一个更快、更广泛的入门体验。 开箱即用,远离繁琐的配置。 提供了一系列大型项目通用的非业务性功能,例如:内嵌服务器、安全管理、运行数据

白鸽 168

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

shiro跨域CORS问题处理

前言 跨域问题的基本处理查看上一篇文章:https://blog.youkuaiyun.com/Mint6/article/details/104468530,这个可以解决大部分问题。 如果是使用的shiro以上步骤都试过了,还有如下问题,请看本文章的解决办法。 问题 把主要提示拷贝出来 A cookie associated with a cross-site resource at htt...

Mint6的博客 4192

springboot,shiro跨域CORS请求,拿不到headers中的token值解决

项目背景: 最近在做一个后台用Spring boot、Shiro、Mybatis plus 、Oauth2,前台用layui的项目.前端在调后台接口的时候需要在浏览器中的headers头中添加token和userId的值(根据业务不同可能传值不一样),后台有一个过滤器,获取到headers中的token和userId,并去验证token是否在有效期内,在进行其他操作,在这个过程中,shiro的过...

一勺菠萝丶的博客 1万+

解决Shiro跨域问题

由于项目需要springboot项目接入了shiro进行登录验证。做法是在在每一个接口的heards部分增加token,后台拿到token后进行验证。在postman测试没问题。但是,前端却一直报options500错误。 原来,是浏览器的同源策略引起的。 什么是同源策略? 源(origin)就是协议、域名和端口号。同源策略是浏览器的一种安全功能,不同源(协议或域名或端口不同)之间不能相...

u010042669的博客 1万+

跨域 以及 shiro解决

跨域 以及 shiro解决 同源策略:协议、域名、端口 作用:能帮助阻隔恶意文档,减少可能被攻击的媒介。 # 但也导致了跨域的问题的出现:前后端分离 # 前端访问后端,不满足同源策略,所以不能访问 1、反向代理解决 # 配置反向代理来实现跨域 # 前端访问代理 # 代理访问后端 # 代理将结果返回给前端 # 从而实现了跨域 2、CORS跨域 CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS的基本思想就

RealGUO的博客 4178

springboot 整合shiro出现的跨域cors问题解决

如果你在后端配置好了跨域配置。还是不生效的。来到这里希望会帮到你! 其实想快速追踪到问题的话。就从打断点开始。 我的猜想是。shiro的过滤器过滤优先级>cors的过滤器,所以才导致的此类问题 结果,果然是这样(以下图片,是我调整后的。所以corsFilter在shiroFilterFactoryBean之上) 所以要想解决这个问题,就要把cors的过滤器的优先级提升。 代码如下: @Bean public FilterRegistrationBean filterRe..

王威振的博客 1664

shiro+vue+springboot跨域

前端结合shiro的话,需要在main.js中为axios添加配置,以便axios在请求头添加Cookie,因为vue默认不会添加Cookie。是否允许跨域使用cookies,如果要跨域使用cookies,可以添加上此请求响应头,值设为true。vue的页面使用vue的router来跳转,router拥有beforeEach方法,用来校验权限。后端添加拦截器,正确处理跨域请求;用于设置允许跨域请求源地址 (预检请求和正式请求在跨域时候都会验证)如此,注解不要,拦截器不要,就可以实现跨域了。

weixin_46223976的博客 725
上一篇: MybatisPlus 数据库字段使用驼峰命名法时碰到的问题
下一篇: springboot整合websocket出错:Error during WebSocket handshake: Unexpected response code: 200
傲娇的鲤鱼
博客等级 码龄10年 88粉丝 53原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值