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 相关文章推荐
如何解决springcloud feign 首次调用100%失败的问题
Jun 23 Java/Android
浅谈自定义校验注解ConstraintValidator
Jun 30 Java/Android
解决ObjectMapper.convertValue() 遇到的一些问题
Jun 30 Java/Android
springboot如何接收application/x-www-form-urlencoded类型的请求
Nov 02 Java/Android
java代码实现空间切割
Jan 18 Java/Android
深入浅出讲解Java8函数式编程
Jan 18 Java/Android
Java实现经典游戏泡泡堂的示例代码
Apr 04 Java/Android
Java 深入探究讲解简单工厂模式
Apr 07 Java/Android
SpringBoot中获取profile的方法详解
Apr 08 Java/Android
Java多线程并发FutureTask使用详解
Jun 28 Java/Android
Java Spring读取和存储详细操作
Aug 05 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
php防止CC攻击代码 php防止网页频繁刷新
2015/12/21 PHP
关于PHP 如何用 curl 读取 HTTP chunked 数据
2016/02/26 PHP
JavaScript接口实现代码 (Interfaces In JavaScript)
2010/06/11 Javascript
基于jQuery+HttpHandler实现图片裁剪效果代码(适用于论坛, SNS)
2011/09/02 Javascript
jQuery Tools tab(幻灯片)
2012/07/14 Javascript
javascript实现youku的视频代码自适应宽度
2015/05/25 Javascript
AngularJS实现Model缓存的方式
2016/02/03 Javascript
Vue数据驱动模拟实现2
2017/01/11 Javascript
Vue.js基础知识小结
2017/01/13 Javascript
详解vue与后端数据交互(ajax):vue-resource
2017/03/16 Javascript
Node.js操作redis实现添加查询功能
2017/05/25 Javascript
redux中间件之redux-thunk的具体使用
2018/04/17 Javascript
layui文件上传控件带更改后数据传值的方法
2019/09/23 Javascript
JavaScript中的null和undefined用法解析
2019/09/30 Javascript
JS XMLHttpRequest原理与使用方法深入详解
2020/04/30 Javascript
js 图片懒加载的实现
2020/10/21 Javascript
下载糗事百科的内容_python版
2008/12/07 Python
Python os模块中的isfile()和isdir()函数均返回false问题解决方法
2015/02/04 Python
Python的Django框架中forms表单类的使用方法详解
2016/06/21 Python
django Serializer序列化使用方法详解
2018/10/16 Python
详解python解压压缩包的五种方法
2019/07/05 Python
详细介绍Python进度条tqdm的使用
2019/07/31 Python
关于Python3 类方法、静态方法新解
2019/08/30 Python
django 中使用DateTime常用的时间查询方式
2019/12/03 Python
Python谱减法语音降噪实例
2019/12/18 Python
用Python开发app后端有优势吗
2020/06/29 Python
django跳转页面传参的实现
2020/09/17 Python
瑞士男士时尚网上商店:Babista
2020/05/14 全球购物
JRE、JDK、JVM之间的关系怎样
2012/05/16 面试题
爱情寄语大全
2014/04/09 职场文书
食品质量与安全专业毕业生求职信
2014/08/11 职场文书
先进员工获奖感言
2014/08/14 职场文书
英语辞职信怎么写
2015/02/28 职场文书
幼儿园教学工作总结2015
2015/05/12 职场文书
Spring Cloud 中@FeignClient注解中的contextId属性详解
2021/09/25 Java/Android
Nginx配置根据url参数重定向
2022/04/11 Servers