被我用烂的DEBUG调试技巧,专治各种搜索不到的问题!
时间:2022-07-22
本文章向大家介绍被我用烂的DEBUG调试技巧,专治各种搜索不到的问题!,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
在开发过程中,遇到问题,我们经常会使用搜索引擎来查找问题的解决方案,然后予以解决。但是有些问题一时半会搜索不到解决方案,需要自己去解决。这里分享下我解决这些问题使用的调试技巧,给大家一个解决问题的新思路!
问题描述
在《我扒了半天源码,终于找到了Oauth2自定义处理结果的最佳方案!》一文中,当JWT令牌过期或者签名不正确时,我们想要自定义网关认证失败的返回结果。这个问题解决起来很简单,只需修改一行代码即可。但是当时查找解决方案确实花费了一番功夫,通过DEBUG源码才找到了Spring Security中提供的自定义配置,解决了该问题。下面讲讲我是如何通过DEBUG源码找到这个解决方案的!
解决过程
- 首先我们需要找到一个切入点,既然问题是由于JWT令牌过期或者签名不正确才产生的,我们很容易想到
RSASSAVerifier
这个关键类,它的verify()
方法是用来验证签名是否正确的,我们可以在该方法上面打个断点DEBUG一下,发现程序执行过程果然会经过这里,要是签名不正确会直接返回false;
- 这时候我们可以查下堆栈信息,了解下这次调用的整个过程,可以看到红框以下的调用都是WebFlux里面的调用,没有参考意义,所以调用最早是从
NimbusReactiveJwtDecoder
类开始的;
- 我们搜索下
NimbusReactiveJwtDecoder
在哪里被使用到了,可以找到又一个关键类ServerHttpSecurity
,我们在网关的安全配置ResourceServerConfig
中曾经用到过它,猜想下如果Spring Security提供了自定义配置,那估计就在这个类里面了;
- 查看下
ServerHttpSecurity
的类注释,我们可以发现它相当于WebFlux版本的Spring Security配置;
/**
* A {@link ServerHttpSecurity} is similar to Spring Security's {@code HttpSecurity} but for WebFlux.
* It allows configuring web based security for specific http requests. By default it will be applied
* to all requests, but can be restricted using {@link #securityMatcher(ServerWebExchangeMatcher)} or
* other similar methods.
**/
- 在我们网关的
ResourceServerConfig
中,我们曾经调用过ServerHttpSecurity
的build()
方法,用于生成SecurityWebFilterChain
;
- 让我们看看这个
build()
方法干了点啥,其中有段比较关键的是它调用了OAuth2ResourceServerSpec
类的configure()
方法;
- 而
OAuth2ResourceServerSpec
类的configure()
方法又调用了JwtSpec
类的configure()
方法;
- 这个
JwtSpec
对象是不会为空的,因为我们在ResourceServerConfig
中调用了OAuth2ResourceServerSpec
类的jwt()
方法创建了它;
-
JwtSpec
类的configure
方法很关键,使用过滤器来进行认证是Spring Security实现认证的老套路了,于是我们找到了默认的认证过滤器BearerTokenAuthenticationWebFilter
;
-
BearerTokenAuthenticationWebFilter
使用了OAuth2ResourceServerSpec
中的entryPoint
来处理认证失败,默认实现为BearerTokenServerAuthenticationEntryPoint
;
- 之后我们在
BearerTokenAuthenticationWebFilter
的filter()
方法,BearerTokenServerAuthenticationEntryPoint
的commence()
方法上分别打个断点,来验证下,调用过程中都经过了,完全正确;
- 也就是说我们只要把默认的认证失败处理器换成我们自定义的就行了,直接通过如下代码把
OAuth2ResourceServerSpec
中的entryPoint
来设置成自定义的即可。
/**
* 资源服务器配置
* Created by macro on 2020/6/19.
*/
@AllArgsConstructor
@Configuration
@EnableWebFluxSecurity
public class ResourceServerConfig {
private final RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
//省略若干代码...
//自定义处理JWT请求头过期或签名错误的结果
http.oauth2ResourceServer().authenticationEntryPoint(restAuthenticationEntryPoint);
//省略若干代码...
return http.build();
}
}
总结
对于一时找不到解决方法的问题,我推荐使用DEBUG源码的方式来解决。首先寻找一个突破口,可以从你熟悉的一些类中去寻找一个必定会执行的方法,然后打断点,进行DEBUG,从调用的栈信息中查找出关键的类,之后通过这些关键类顺藤摸瓜就能找解决方法了!
项目源码地址
https://github.com/macrozheng/springcloud-learning/tree/master/micro-oauth2
- Java 关于接口的那点事儿
- 论 Java 中的内存分配
- Javascript基础回顾 之(一) 类型
- Javascript基础回顾 之(三) 面向对象
- Javascript基础回顾 之(二) 作用域
- 一不小心写了个WEB服务器
- 遍历算法(1)
- Membership三步曲之入门篇 - Membership基础示例
- Java-String.intern的深入研究
- 从Membership 到 .NET4.5 之 ASP.NET Identity
- Membership三步曲之进阶篇 - 深入剖析Provider Model
- java finally深入探究
- 背后的故事之 - 快乐的Lambda表达式(一)
- 背后的故事之 - 快乐的Lambda表达式(二)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- HashMap源码分析 - jdk8
- HashMap源码分析 - JDK7和JDK8有什么区别
- 线程应用 - 中断interrupt详解
- ThreadLocal全面解析
- tomcat类加载机制了解一下
- tomcat-超详细的启动流程(init)
- tomcat-超详细的启动流程(start)
- NIO学习(一)Buffer缓冲区
- NIO学习(二)Channel通道与Selectors选择器
- Spring学习(一)bean的初始化过程
- Spring学习(二)bean的循环依赖
- Spring学习(三)后置处理器BeanPostProcessor
- Spring学习(四)AOP基础
- Spring知识点(五)代理模式
- Spring知识点(六)bean的生命周期