介绍
跟踪调试Spring Security OAuth2.0的密码模式获取token过程,了解记录获取token的大体流程,便于后续遇到问题debug调试。这里调试使用的spring security版本5.7.6是较低的版本,截图中也会看到很多类被标记@Deprecated,低版本熟悉了再升级高版本也算是一个升级打怪的过程吧。高版本的SAS授权源码和本文记录有差异,后续也会尝试使用新版的授权方式实践一下。另外本次调试的前提是搭建好了授权服务(这里不展开搭建过程),且本次调试请求没有经过网关,只有auth和admin服务。auth服务提供授权、admin服务提供查询数据库服务。本文跟踪调试的是请求达到自定义页面/login方法后的过程。
UsernamePasswordAuthenticationFilter断点不进入问题
请求/oauth/token获取token时,可以看到FilterChainProxy里面一共有12个拦截器,但是未看到UsernamePassword相关的Filter,打了断点也未进入断点。疑惑了很久在DS上查询发现问题原因:spring securiy的认证分为oauth认证和security认证。请求/oauth/token时是由oauth委托AuthenticationManager完成,并不经过UsernamePasswordAuthenticationFilter,请求/oauth/token以外的路径时会经过UsernamePasswordAuthenticationFilter过滤器。另外翻一下源码包可以发现UsernamePasswordAuthenticationFilter类在spring-security-web.jar包,而ResourceOwnerPasswordTokenGranter类则位于spring-security-oauth.jar包下。所以他们是两种不同的认证实现方式。因此想要debug进入UsernamePasswordAuthenticationFilter断点则需要访问/auth/token之前的路径。比如这里访问:http://localhost:9002/login 即可看到FilterChainProxy加载了13个过滤器,包括UsernamePasswordAuthenticationFilter。
UsernamePasswordAuthenticationFilter断点调试
F9进入到doFilter()方法, UsernamePasswordAuthenticationFilter的filter方法继承自父类。
F7进入UsernamePasswordAuthenticationFilter#attemptAuthentication()方法,该方法把请求的参数封装进UsernamePasswordAuthenticationToken类(实现了Authentication接口)中。getAuthenticationManager()方法返回的是AuthenticationManager,这又回到了oauth认证
AuthenticationManager接口又把请求委托给ProviderManager#authticate()处理,最后委托给了AuthenticationProvider,前面的一列接口类都是传话的,AuthenticationProvider的实现类DaoAuthenticationProvider才是最后干活的。
AuthenticationProvider有多个实现类,怎么最终确认是DaoAuthenticationProvider干活的呢?确认过程就是上面截图中的provider.supports(toTest)断言计算出来的,toTest的泛型是UsernamePasswordAuthenticationToken.class,而DaoAuthenticationProvider的supports方法写死了自己匹配支持的泛型上面toTest的泛型是UsernamePasswordAuthenticationToken,因此最终匹配到的打工人就是DaoAuthenticationProvider类。
继续往下走
接下来就是熟悉的获取用户数据流程,不再展开。
这里发现在似乎认证后就没了?推测UsernamePasswordAuthenticationFilter过滤器主要用于定制化需求,这里认证完成后说明用户身份信息合法,接下来可以做一些其他操作,比如生成token,jwt,存入redis,跳转页面等,如果不合法跳转到错误页面,登录页面等,待完善。