Spring Security中用JWT退出登录时遇到的坑


Posted in Java/Android onOctober 16, 2021

最近有个粉丝提了个问题,说他在Spring Security中用JWT做退出登录的时无法获取当前用户,导致无法证明“我就是要退出的那个我”,业务失败!经过我一番排查找到了原因,而且这个错误包括我自己的大部分人都犯过。

Session会话

之所以要说Session会话,是因为Spring Security默认配置就是有会话的,所以当你登录以后Session就会由服务端保持直到你退出登录。只要Session保持住,你的请求只要进入服务器就可以从 ServletRequest 中获取到当前的 HttpSession ,然后会根据 HttpSession 来加载当前的 SecurityContext 。相关的逻辑在Spring Security默认的过滤器 SecurityContextPersistenceFilter 中,有兴趣可以看相关的源码。

而且默认情况下 SecurityContextPersistenceFilter 的优先级是高于退出过滤器 LogoutFilter 的,所以能够保证有Session会话的情况下退出一定能够获取当前用户。

无Session会话

使用了JWT后,每次请求都要携带 Bearer Token 并且被专门的过滤器拦截解析之后才能将用户认证信息保存到 SecurityContext 中去。参考Spring Security实战干货教程中的Token认证实现 JwtAuthenticationFilter ,相关逻辑为:

// 当token匹配         
if (jwtToken.equals(accessToken)) {
    // 解析 权限集合  这里
    JSONArray jsonArray = jsonObject.getJSONArray("roles");
    List<String> roles = jsonArray.toList(String.class);
    String[] roleArr = roles.toArray(new String[0]);

    List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(roleArr);
    User user = new User(username, "[PROTECTED]", authorities);
    // 构建用户认证token
    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user, null, authorities);
    usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
    // 放入安全上下文中
    SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
} else {
    // token 不匹配
    if (log.isDebugEnabled()){
        log.debug("token : {}  is  not in matched", jwtToken);
    }
    throw new BadCredentialsException("token is not matched");
}

为什么退出登录无法获取当前用户

分析了两种情况下用户认证信息的安全上下文配置后,我们回到问题的本身。来看看为什么用JWT会出现无法获取当前认证信息的原因。在 HttpSecurity 中,那位同学是这样配置 JwtAuthenticationFilter 的顺序的:

httpSecurity.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
我们再看看 Spring Security 过滤器排序图:

Spring Security中用JWT退出登录时遇到的坑

也就说LogoutFilter执行退出的时候,JWT还没有被 JwtAuthenticationFilter 拦截,当然无法获取当前认证上下文 SecurityContext 。

解决方法

解决方法就是必须在 LogoutFilter 执行前去解析JWT并将成功认证的信息存到 SecurityContext 。我们可以这样配置:

httpSecurity.addFilterBefore(jwtAuthenticationFilter, LogoutFilter.class)
这样问题就解决了,你只要实现把当前JWT作废掉就退出登录了。

到此这篇关于Spring Security中用JWT退出登录时遇到的坑的文章就介绍到这了,更多相关Spring Security JWT退出登录内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Java/Android 相关文章推荐
Java方法重载和方法重写的区别到底在哪?
Jun 11 Java/Android
一篇带你入门Java垃圾回收器
Jun 16 Java/Android
springboot利用redis、Redisson处理并发问题的操作
Jun 18 Java/Android
解决SpringCloud Feign传对象参数调用失败的问题
Jun 23 Java/Android
Spring Data JPA的Audit功能审计数据库的变更
Jun 26 Java/Android
Java使用httpRequest+Jsoup爬取红蓝球号码
Jul 02 Java/Android
java设计模式--七大原则详解
Jul 21 Java/Android
解析mybatis-plus中的resultMap简单使用
Nov 23 Java/Android
spring cloud eureka 服务启动失败的原因分析及解决方法
Mar 17 Java/Android
JavaWeb实现显示mysql数据库数据
Mar 19 Java/Android
解决springboot druid数据库连接失败后一直重连的方法
Apr 19 Java/Android
Android studio 简单计算器的编写
May 20 Java/Android
Java实现房屋出租系统详解
Oct 05 #Java/Android
Java Spring 控制反转(IOC)容器详解
Java spring定时任务详解
JAVA API 实用类 String详解
Oct 05 #Java/Android
SpringCloud之@FeignClient()注解的使用方式
Sep 25 #Java/Android
springboot中rabbitmq实现消息可靠性机制详解
Sep 25 #Java/Android
Spring Cloud 中@FeignClient注解中的contextId属性详解
Sep 25 #Java/Android
You might like
PHP5与MySQL数据库操作常用代码 收集
2010/03/21 PHP
PHP的preg_match匹配字符串长度问题解决方法
2014/05/03 PHP
php生成图片验证码的实例讲解
2015/08/03 PHP
php实现数据库的增删改查
2017/02/26 PHP
PHP巧妙利用位运算实现网站权限管理的方法
2017/03/12 PHP
thinkPHP5.1框架路由::get、post请求简单用法示例
2019/05/06 PHP
图片完美缩放
2006/09/07 Javascript
javascript 简练的几个函数
2009/08/29 Javascript
输入框的字数时时统计—关于 onpropertychange 和 oninput 使用
2011/10/21 Javascript
jQuery+canvas实现简单的球体斜抛及颜色动态变换效果
2016/01/28 Javascript
JavaScript获取客户端IP的方法(新方法)
2016/03/11 Javascript
JQuery DIV 动态隐藏和显示的方法
2016/06/23 Javascript
bootstrap table使用入门基本用法
2017/05/24 Javascript
Node.js学习教程之HTTP/2服务器推送【译】
2017/10/31 Javascript
JavaScript 五大常见函数
2018/03/23 Javascript
vue后台管理之动态加载路由的方法
2018/08/13 Javascript
小程序云开发初探(小结)
2018/10/24 Javascript
JavaScript通如何过RGraph实现动态仪表盘
2020/10/15 Javascript
python实现的简单FTP上传下载文件实例
2015/06/30 Python
简单谈谈Python流程控制语句
2016/12/04 Python
轻量级的Web框架Flask 中模块化应用的实现
2017/09/11 Python
python 输出所有大小写字母的方法
2019/01/02 Python
Python中filter与lambda的结合使用详解
2019/12/24 Python
在pycharm中为项目导入anacodna环境的操作方法
2020/02/12 Python
为什么称python为胶水语言
2020/06/16 Python
css3中新增的样式使用示例附效果图
2014/08/19 HTML / CSS
在HTML5中使用MathML数学公式的简单讲解
2016/02/19 HTML / CSS
雅萌 (YA-MAN) :日本美容家电领域的龙头企业
2017/05/12 全球购物
戴尔新加坡官网:Dell Singapore
2020/12/13 全球购物
介绍一下UNIX启动过程
2013/11/14 面试题
节能环保演讲稿
2014/08/28 职场文书
大学生党性分析材料
2014/12/19 职场文书
婚礼父母答谢词
2015/01/04 职场文书
奖金申请报告模板
2015/05/15 职场文书
python爬虫请求库httpx和parsel解析库的使用测评
2021/05/10 Python
Ubuntu Server 安装Tomcat并配置systemctl
2022/04/28 Servers