第四阶段15-关于权限,处理解析JWT时的异常,跨域请求,关于Spring Security的认证流程
处理解析JWT时的异常
由于解析JWT是在过滤器中执行的,而过滤器是整个服务器端中最早接收到所有请求的组件,此时,控制器等其它组件尚未运行,则不可以使用此前的“全局异常处理器”来处理解析JWT时的异常(全局异常处理器只能处理控制器抛出的异常),也就是说,在过滤器中只能使用try...catch
语法来处理异常!
为了便于表示需要响应到客户端的结果,仍推荐使用JsonResult
封装相关信息,而响应到客户端的结果应该是JSON格式的,则需要将JsonResult
对象转换成JSON格式的字符串!
在项目中添加fastjson
依赖项,此依赖项可以实现Java对象与JSON格式的字符串的相互转换:
<!-- fastjson:实现对象与JSON的相互转换 -->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version>
</dependency>
在处理异常之前,还应该在ServiceCode
中补充相关的业务状态码,例如:
ERR_JWT_EXPIRED(60000),
ERR_JWT_MALFORMED(60100),
ERR_JWT_SIGNATURE(60200),
然后,调整JwtAuthorizationFilter
中解析JWT的代码片段:
Claims claims = null;
response.setContentType("application/json; charset=utf-8");
try {claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
} catch (SignatureException e) {String message = "非法访问!";log.warn("解析JWT时出现SignatureException,响应消息:{}", message);JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_SIGNATURE, message);PrintWriter printWriter = response.getWriter();printWriter.println(JSON.toJSONString(jsonResult));printWriter.close();return;
} catch (MalformedJwtException e) {String message = "非法访问!";log.warn("解析JWT时出现MalformedJwtException,响应消息:{}", message);JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_MALFORMED, message);PrintWriter printWriter = response.getWriter();printWriter.println(JSON.toJSONString(jsonResult));printWriter.close();return;
} catch (ExpiredJwtException e) {String message = "您的登录信息已过期,请重新登录!";log.warn("解析JWT时出现ExpiredJwtException,响应消息:{}", message);JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_EXPIRED, message);PrintWriter printWriter = response.getWriter();printWriter.println(JSON.toJSONString(jsonResult));printWriter.close();return;
}
关于认证信息中的“当事人”
认证信息中的“当事人”可以通过@AuthenticationPrincipal
注入到方法(控制器的方法)的参数中,在访求处理过程中,可能需要获取“当事人”的ID、用户名等数据,所以,应该自定义数据类型表示“当事人”(Spring Security也希望你这样做,所以,在认证结果的信息中的“当事人”被声明为Object
类型)!
在项目的根包下创建security.LoginPrincipal
类:
package cn.tedu.csmall.passport.security;import lombok.Data;import java.io.Serializable;/*** 当事人类型,就是成功通过认证的用户信息类型* * @author java@tedu.cn* @version 0.0.1*/
@Data
public class LoginPrincipal implements Serializable {/*** 当事人ID*/private Long id;/*** 当事人用户名*/private String username;}
然后,调整JwtAuthorizationFilter
中的相关代码:
Long id = claims.get("id", Long.class);
String username = claims.get("username", String.class);
log.debug("从JWT中解析得到的管理员ID:{}", id);
log.debug("从JWT中解析得到的管理员用户名:{}", username);// 基于解析JWT的结果创建认证信息
LoginPrincipal principal = new LoginPrincipal();
principal.setId(id);
principal.setUsername(username);// 暂不关心其它代码
在控制器中处理请求的方法的参数列表中,可以通过@AuthenticationPrincipal
注入LoginPrincipal
类型的参数,在处理请求的过程中,可以通过此参数获取当事人的具体数据:
@GetMapping("")
public JsonResult<List<AdminListItemVO>> list(// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 自定义的当事人类型@ApiIgnore @AuthenticationPrincipal LoginPrincipal loginPrincipal) {log.debug("开始处理【查询管理员列表】的请求,参数:无");log.debug("当事人:{}", loginPrincipal);log.debug("当事人的ID:{}", loginPrincipal.getId());log.debug("当事人的用户名:{}", loginPrincipal.getUsername());List<AdminListItemVO> list = adminService.list();return JsonResult.ok(list);
}
关于权限
目前,当管理员登录成功后,服务器端生成的JWT中并不包含此管理员的权限信息,所以,此管理员后续携带JWT提交请求时,服务器端也无法根据此JWT直接获取管理员的权限列表,更加不能把正确的权限列表存入到SecurityContext
中的认证信息中,所以,无法检查管理员的权限!
可以在管理员登录成功后,将此管理员的权限列表也写入到JWT中!
**注意:**由于权限列表并不是一般的字面值数据,生成到JWT中后,将无法还原回原本的集合类型!应该先将权限列表转换成JSON格式的字符串,后续,再根据此JSON数据还原回原本的列表!
在AdminServiceImpl
中的login()
方法中调整:
// 将通过认证的管理员的相关信息存入到JWT中
// 准备生成JWT的相关数据
Date date = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000);
AdminDetails principal = (AdminDetails) authenticationResult.getPrincipal();
Map<String, Object> claims = new HashMap<>();
claims.put("id", principal.getId());
claims.put("username", principal.getUsername());
Collection<GrantedAuthority> authorities = principal.getAuthorities(); // 新增
String authoritiesJsonString = JSON.toJSONString(authorities); // 新增
claims.put("authoritiesJsonString", authoritiesJsonString); // 新增
然后,在JwtAuthorizationFilter
中调整:
Long id = claims.get("id", Long.class);
String username = claims.get("username", String.class);
String authoritiesJsonString = claims.get("authoritiesJsonString", String.class); // 新增
log.debug("从JWT中解析得到的管理员ID:{}", id);
log.debug("从JWT中解析得到的管理员用户名:{}", username);
log.debug("从JWT中解析得到的管理员权限列表JSON:{}", authoritiesJsonString);// ========== 将原有的“山寨”权限的代码替换为以下代码 ==========
// 将JSON格式的权限列表转换成Authentication需要的类型(Collection<GrantedAuthority>)
List<SimpleGrantedAuthority> authorities =JSON.parseArray(authoritiesJsonString, SimpleGrantedAuthority.class);
最后,在控制器中,可以继续使用@PreAuthroize
注解检查权限!
**注意:**在API文档的调试中,需要使用新的JWT数据!
关于清空SecurityContext
目前,当使用有效的JWT提交请求后,即使下一次(间隔时间不能太久)不携带JWT再次提交请求,也是服务器端认可的!
这是因为:当使用有效的JWT提交请求后,JwtAuthorizationFilter
会将此JWT中的信息创建为Authentication
对象,并将此Authentication
保存到SecurityContext
中!而SecurityContext
是基于Session的,所以,在Session未过期之前,即使后续的请求没有携带JWT,Spring Security仍能从Session中找到SecurityContext
中的Authentication
对象,会视为此次访问与此前的访问是同一个客户端。
如果认为这是一种不合理的表现,可以在JwtAuthorizationFilter
中,在执行过滤之初,就不由分说的**清空SecurityContext
**即可!
// 清除SecurityContext中的数据
SecurityContextHolder.clearContext();
处理未登录的错误
当客户端没有携带JWT,却向需要通过认证的URL发起请求,默认将响应403
错误,这种问题需要在Spring Security的配置类中的void configure(HttpSecurity http)
方法中进行配置:
// 处理“需要通过认证,但是实际上未通过认证就发起的请求”导致的错误
http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {String message = "未检测到登录,请登录!(在开发阶段,看到此提示时,请检查客户端是否携带了JWT向服务器端发起请求)";JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_UNAUTHORIZED, message);response.setContentType("application/json; charset=utf-8");PrintWriter printWriter = response.getWriter();printWriter.println(JSON.toJSONString(jsonResult));printWriter.close();}
});
关于Spring Security的认证流程
使用axios携带JWT发起请求
当需要携带JWT发起请求时,根据业内惯例,JWT应该放在请求头的Authorization
属性中,则使用axios时需要自定义请求头,其语法是:
// 以下调用的create()表示创建一个axios实例,此函数的参数是一个对象,用于表示新创建的axios的参数
this.axios.create({'headers': {'Authorization': jwt}}).get(); // 与此前使用相同,在此处调用get()或post()发起请求
关于复杂请求的预检机制导致的跨域问题
在使用了Spring Security框架的项目中,当客户端携带JWT向服务器端发起异步请求,默认会出现跨域访问的错误(即使在服务器端通过Spring MVC配置类允许跨域,此问题依然存在),可以在Spring Security的配置类中的void configure(HttpSecurity http)
方法中添加配置,以解决此问题:
http.cors();
出现此问题的根本原因在于:如果客户端提交的请求自定义了请求头中的特定属性(例如配置了请求头中的Authorization
属性),此请求会被视为“复杂请求”,客户端的浏览器会先向服务器端的此URL发起OPTIONS
类型的请求执行“预检(PreFlight)”,如果预检不通过,则不允许提交原本尝试提交的请求。
所以,可以在Spring Security的配置类中,对所有OPTIONS
类型的请求“放行”,即可解决此问题:
http.authorizeRequests() // 配置URL的访问控制// 重要,以下2行代码表示:对所有OPTIONS类型的请求“放行”.mvcMatchers(HttpMethod.OPTIONS, "/**").permitAll().mvcMatchers(urls).permitAll().anyRequest().authenticated();
或者,通过http.cors();
也可以解决此问题,此方法的本质是启用了Spring Security自带的CorsFilter
过滤器,此过滤器会对OPTIONS
请求放行。
相关文章:
第四阶段15-关于权限,处理解析JWT时的异常,跨域请求,关于Spring Security的认证流程
处理解析JWT时的异常 由于解析JWT是在过滤器中执行的,而过滤器是整个服务器端中最早接收到所有请求的组件,此时,控制器等其它组件尚未运行,则不可以使用此前的“全局异常处理器”来处理解析JWT时的异常(全局异常处理器…...
毕业设计 基于51单片机的指纹红外密码电子锁
基于51单片机的指纹红外密码电子锁1、项目简介1.1 系统框架1.2 系统功能2、部分电路设计2.1 STC89C52单片机最小系统电路设计2.2 矩阵按键电路电路设计2.3 液晶显示模块电路设计3、部分代码展示3.1 LCD12864显示字符串3.2 串口初始化实物图1、项目简介 选题指导,项…...
【JavaWeb】数据链路层协议——以太网 + 应用层协议——DNS
以太网 以太网不是一个具体的网络,而是一个技术标准,主要应用于数据链路层和物理层。 以太网数据帧结构 以太网的数据帧结构由三部分构成: 帧头 载荷 帧尾 其中的MAC地址是六位,这样就比IPV4所表示的地址大很多,…...
docker 容器安装 python jre
Dockerfile FROM python:2.7.11-alpine RUN mkdir /usr/local/java WORKDIR /usr/local/java # 5.更改 Alpine 的软件源为阿里云,默认从官方源拉取比较慢 RUN echo http://mirrors.aliyun.com/alpine/v3.10/main/ > /etc/apk/repositories && \ echo…...
Linux下将C++程序打包成动态库静态库方法
之前在这篇文章里介绍过动态库和静态库的理论部分,这篇文章主要介绍下实际的操作步骤: 静态链接库生成 gcc -c main.cpp -o main.o ar -rc libmain.a main.o sudo cp libmain.a /usr/local/lib 调用即可解释一下上面的命令:前两步生成了libmain.a sudo…...
Centos7 服务器基线检查处理汇总
1、服务器超时设置 问题描叙 TMOUT的值大于key2且小于等于{key2}且小于等于key2且小于等于{key1}视为合规 查看命令:export检测结果 超时时间:0处理方式 备份/etc/profile文件 cp /etc/profile /etc/profile_bak编辑profile文件 vim /etc/profile修改/新增 TMO…...
PaddleOCR遇到 lanms-neo问题处理
在window环境中安装PaddleOCR依赖是真的蛋疼,关键官方论坛里也都没有具体的解决方案。吐槽。。。吐槽。。。 我在 “windows安装lanms-neo问题处理”文章中看到lanms-neo问题全过程解决。个人觉得文档说明不是很细致,导致我按步骤执行,还是安…...
coreldraw2023安装包下载及新功能介绍
对于广告标识业来说 coreldraw这个软件,对我们来说绝对不陌生,我从2008年开始接触到广告制作,到现在已经13多年了,从一开始的coreldraw 9红色的热气球开始。就被这个强大的软件所吸引,他有强大的排榜功能已经对位图的处…...
Nginx 负载均衡服务失败场景
nginx可以配置负载均衡,我们可以通过配置实现nginx负载均衡。这里部署了两个服务producter-one和producter-one2。 upstream proxyproducter-one {server producter-one:8080 weight1;server producter-one2:8080 weight1;}# 访问其他服务server {listen 9090…...
开学季哪个电容笔好?2023口碑最好电容笔推荐
虽说苹果原装的电容笔非常好用,性能也非常不错,但由于价格昂贵,普通的学生是没办法购买的,再加上重量比较大,使用时间长了,难免会让人感觉到疲劳。如果仅仅是为了学习记笔记,那就没必要再去购买…...
经验分享-如何使用http调用chatGPT-3.5-turbo模型API
今天上午,就在工作群里收到了关于openAI发布chatGPT官方模型的消息分享。openAI这次的动作真的很快啊,没想到这么快就直接发布了chatGPT目前所使用的模型api。据Open AI在官方消息,本次开放了ChatGPT和Whisper的模型API,可以供用户…...
【C#】yyyy-MM-dd HH:mm:ss 时间格式 时间戳 全面解读超详细
C# 日期转字符串 实例化一个时间字符串 DateTimeFormatInfo dfInfonew DateTimeFormatInfo(); dfInfo.ShortDatePattern "yyyy/MM/dd hh:mm:ss:ffff"; DateTime dt Convert.ToDateTime("2019/07/01 18:18:18:1818", dfInfo);日期转字符串 string dat…...
基于神经网络的滑模鲁棒控制
目录 前言 1.双关节机械手臂模型 2.神经网络自适应律设计 3. 滑模控制律设计 4. 仿真分析 4.1 仿真模型 4.2 仿真结果 4.3 小结 5 学习问题 前言 上一篇文章我介绍了神经网络补偿的机理,只不过控制律不同,本章我们结合滑模理论设计控制律&#…...
2023年融资融券研究报告
第一章 行业概况 融资融券是证券交易市场上的两种金融衍生品交易方式,主要用于股票、债券等证券的融资和投资。 融资是指投资者向证券公司借入资金购买证券,以期望股票价格上涨后卖出获得利润。融资需支付一定的利息和费用,利息根据借入的资…...
Nodejs环境配置 | Linux安装nvm | windows安装nvm
文章目录一. 前言二. Linux Nodejs环境配置1. 安装nvm2. 配置npm三. Windows Nodejs环境配置1. 安装nvm2. 配置npm四. nvm基本使用一. 前言 由于在实际开发中一些不同的项目需要不同的npm版本来启动,所以本篇文章会基于nvm这个node版本管理工具来进行Linux和Winodw…...
显示接口测试
背景需求两个显示器连接到一台PC,期望每台显示器可以单独显示,在一台显示器显示时,另外一台显示器同PC的连接断开,即系统下查看到连接状态为disconnected。同时在显示器上图形化显示当前显示器编号。如下图,期望当显示…...
Tcl_Init error: Can‘t find a usable init.tcl in the following directories
目录 问题 解决 小结 问题 最近在研究开源波形显示软件gtkwave时,Ubuntu18.04下编译打包完成,移植到另一个电脑上运行时,出现以下错误,如图: 擦掉的部分是一些路径信息,这个错误提示意味着您的系统中缺少所需的 Tcl 初始化文件,路径下确实没有init.tcl文…...
进程控制(详解)
进程控制上篇文章介绍了进程的相关概念,形如进程的内核数据结构task_struct 、进程是如何被操作系统管理的、进程的查看、进程标识符、进程状态、进程优先级、已经环境变量和进程地址空间等知识点; 本篇文章接着上篇文章继续对进程的控制进行展开&#x…...
瓜子大王稳住基本盘,洽洽食品做对了什么?
2月24日,洽洽食品披露2022年业绩快报,公司预计实现营收总收入68.82亿元,同比增长14.98%, 实现归母净利润9.77 亿元,同比增长5.21%,业绩基本符合市场预期。来源:洽洽食品2022年度业绩快报2022年,瓜子大王洽洽…...
【音视频安卓开发 (十一)】jni基础
要使用jni开发需要包含jni.h头文件JNIEXPORT JNI : 是一个关键字,不能少(编译能通过),标记为该方法可以被外部调用jstring : 代表java中的stringJNICALL: 也是一个关键字,可以少的jni callJNIENV : 这是c和java相互调用…...
通过FRP搭建内网穿透,实现域名访问局域网本机
1我的目标:实现通过域名访问局域网tomcat服务,域名访问方便本地微信调试2思路:(1)用服务器搭建内网穿透利用FRP实现穿透,frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、…...
Pytorch 代码复现终极指南【收藏】
修改自:https://zhuanlan.zhihu.com/p/532511514我在刚接触pytorch的时候搜到了这个大佬的文章,当时最后天坑部分没有看的太明白,直到今天我也遇到的相同的问题,特来做一点点补充,方便大家理解。上述大佬文章的简版内容…...
iOS 后台运行
背景:app有在后台运行的需求 常用的后台常驻实现方法 1.Audio(音乐播放软件) 应用在后台播放无声的音频文件,只要播放不断,后台可一直活着,苹果审核人员如果发现,会被拒,有可能会…...
软设下午题第一大题--数据流图(做题)
软设下午第一大题一、数据流图(Data Flow Diagram,简称DFD)1、基本图形元素元素(1)外部实体(External Agent)(2)数据存储(Data Store)(3ÿ…...
springboot内嵌Tomcat 安全漏洞修复
漏洞扫描提示的是tomcat-embed-core[CVE-2020-1938],解决方式是升级tomcat的版本。 该漏洞影响的版本: Apache Tomcat 9.x < 9.0.31 Apache Tomcat 8.x < 8.5.51 Apache Tomcat 7.x < 7.0.100 Apache Tomcat 6.x 其余的安全漏洞也可以通过…...
Android OTA 相关工具(三) A/B 系统之 bootctl 工具
文章目录1. bootctl 的编译2. bootctl 的帮助信息3. bootctl 的用法1. hal-info2. get-number-slots3. get-current-slot4. mark-boot-successful5. set-active-boot-slot6. set-slot-as-unbootable7. is-slot-bootable8. is-slot-marked-successful9. get-suffix10. set-snaps…...
【Flink】org.apache.flink.table.api.ValidationException: SQL validation failed
遇到问题如下 Exception in thread "main" org.apache.flink.table.api.ValidationException: SQL validation failed. From line 1, column 15 to line 1, column 17: Object aaa not found at org.apache.flink.table.planner.calcite.FlinkPlannerImpl.orgat org.…...
宏基因组鉴定病毒流程中需要的生物信息工具
谷禾健康 许多流行病的爆发都是病毒引起的,面对新的传染性基因组出现的最佳策略是及时识别,以便于在感染开始时立即实施相应措施。 目前可用的诊断测试仅限于检测新的病理因子。适用于同时检测存在的任何病原体的高通量方法可能比使用基于当前方法的大量…...
Doris入门篇-分区分桶实验
简介 测试分区分桶效果。 分区的基本操作 添加分区 ALTER TABLE v2x_olap_database.government_car ADD PARTITION p20221203 VALUES LESS THAN ("2022-12-04");动态分区表不能添加分区,需要转为手动分区表。 查看分区 show partitions from <表…...
Spring-Xml配置
一、Spring 简介 1.简介 文档下载地址:Index of /spring-framework/docs 1.简介 Spring framework 是 Spring 基础框架 学习Spring 家族产品 Spring framework SpringBoot SpringCloud Spring 能用来做什么 开发 WEB 项目 微服务 分布式系统 Spring framew…...
58同城乌鲁木齐网站建设/网络运营推广具体做什么工作
伪造队形(FFT)题目描述Tukkun带着他的合唱队去环形音乐厅参加演出.上场前,Tukkun发现了严重的问题:音乐厅的工作人员把他们的合唱队形搞错了.具体来说,Tukkun的合唱队有N个人围成一圈,身高按照顺时针顺序 ...CSS学习笔记08 浮动从CSS学习笔记05 display属性一…...
阿里云网站建设认证答案/百度论坛
SQL Server 5030错误解决办法 今天在使用SQL Server时,由于之前创建数据库忘记了设置Collocation,数据库中插入中文字符都是乱码,于是到DataBase的Options中修改Collocation,出现了The database could not be exclusively locked …...
怎么做广告宣传效果好/seo关键词排名优化是什么
2019独角兽企业重金招聘Python工程师标准>>> 对于每一个iOS开发人员来说,最终无疑就是将自己开发的APP上线到AppStore,让更多的人去用自己写的软件。 试想一下,哪天走在街上看到某个人在用你写的音乐软件听着歌,那是一…...
商丘网站设计/5118大数据平台官网
Log4j2 使用教程Log4j2 的好处就不在这里一一列举了,如果你搜了2,说明你对它一定有兴趣,并且想了解它,使用它。一、下载log4j2 ,基本上你只需要导入下面两个jar包即可: log4j-api-2.11.0.jarlog4j-cor…...
java做网站好吗/做企业网站哪个平台好
动态规划0-1背包问题 问题描写叙述:给定n种物品和一背包。物品i的重量是wi。其价值为vi,背包的容量为C。问应怎样选择装入背包的物品,使得装入背包中物品的总价值最大?对于一种物品,要么装入背包,要么不装。所以对于一…...
展示型手机网站/微信营销的方法和技巧
2019独角兽企业重金招聘Python工程师标准>>> (1)Linux下各目录的作用 1)/bin/-----存放系统命令的目录,普通用户和超级用户都可以执行。不过放在/bin下的命令在单用户模式下也可以执行 2)/sbin/-----保存与…...