https://www.jianshu.com/p/e98cdf23b991
前言
上一期我们分享了Spring Security是如何通过AbstractAuthenticationProcessingFilter向Web应用向基于HTTP、浏览器的请求提供身份验证服务的。
这一次我们针对最常用,也是Spring Security默认在HTTP上使用的验证过滤器转存失败重新上传取消即基于用户名和密码的身份验证过滤器是如何与核心进行交互进行展开说明。目的是希望让大家对如何在Spring Security的核心上完成一个指定的身份验证协议的扩展工作,已经涉及相关主要组件及其角色职责有个初步的了解。
这一期的内容如果有了前几期对身份验证核心的背景,相对来说比较的简单,因为整个流程就是在原有的基础上更加具体化了场景:身份验证的数据来源是用户提交的请求,验证的凭证是用户名和密码。由于这样的原因,这一期更像是对前几期的一个综合性的应用总结。
第四期 UsernamePasswordAuthenticationFilter详细说明
本期的任务清单
- 了解UsernamePasswordAuthenticationFilter的职责和实现
1. 了解UsernamePasswordAuthenticationFilter的职责和实现
UsernamePasswordAuthenticationFilter类的说明
UsernamePasswordAuthenticationFilter是AbstractAuthenticationProcessingFilter针对使用用户名和密码进行身份验证而定制化的一个过滤器。
在一开始我们先通过下面的配图来回忆一下我们的老朋友AbstractAuthenticationProcessingFilter的在框架中的角色与职责。
AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter在整个身份验证的流程中主要处理的工作就是所有与Web资源相关的事情,并且将其封装成Authentication对象,最后调用AuthenticationManager的验证方法。所以UsernamePasswordAuthenticationFilter的工作大致也是如此,只不过在这个场景下更加明确了Authentication对象的封装数据的来源和形式——使用用户名和密码。
接着我们再对转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消的实现类,DaoAuthenticationProvider针对UsernamePasswordAuthenticationToken的大部分逻辑都是通过AbstractUserDetailsAuthenticationProvider完成的。比如针对ProviderManager询问是否支持当前Authentication的supports方法:
public boolean supports(Class> authentication) {return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));}
可能有些同学对isAssignableFrom方法比较陌生,这是一个判断两个类之间是否存在继承关系使用的判断方法,DaoAuthenticationProvider会判断当前的Authentication的实现类是否是UsernamePasswordAuthenticationToken它本身,或者是扩展了UsernamePasswordAuthenticationToken的子孙类。返回true的场景只有一种,便是当前的Authentication是UsernamePasswordAuthenticationToken实现,换言之便是DaoAuthenticationProvider设计上需要进行处理的某种特定的验证协议的信息载体的实现。
核心验证逻辑:Authentication authenticate(Authentication authentication)
完成了是否支持的supports验证后,ProviderMananger便会全权将验证工作交由DaoAuthenticationProvider进行处理了。与ProviderMananger最不同一点是,在DaoAuthenticationProvider的视角里,当前的Authentication最起码一定是UsernamePasswordAuthenticationToken的形式了,不用和ProviderMananger一样因为匮乏信息而不知道干什么。
在DaoAuthenticationProvider分别会按照预先设计一样分别从principal和credentials获取用户名和密码进行验证。
String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED": authentication.getName();String presentedPassword = authentication.getCredentials().toString();
接着便是按照我们熟悉的预先设计流程,通过UserDetailsService使用username获取对应的UserDetails,最后通过对比密码是否一致,向PrivoderManager返回最终的身份验证结果与身份信息。这样一个特定场景使用用户名和密码的验证流程就完成了。
小结
我们先来总结下,当前出现过的针对用户名和密码扩展过的类与其为何被扩展的原因。
- UsernamePasswordAuthenticationFilter扩展AbstractAuthenticationProcessingFilter,因为需要从HTTP请求中从指定名称的参数获取用户名和密码,并且传递给验证核心;
- UsernamePasswordAuthenticationToken扩展Authentication,因为我们设计了一套约定将用户名和密码放入了指定的属性中以便核心读取使用;
- DaoAuthenticationProvider 扩展AuthenticationProvider,因为我们需要在核心中对UsernamePasswordAuthenticationToken进行处理,并按照约定读出用户名和密码使其可以进行身份验证操作。
客制化验证协议过程中涉及扩展的类
结尾
本章的重点是介绍特定场景下框架是如何通过扩展指定组件来完成预设验证逻辑的交互过程。其实整个验证工作核心部分是在DaoAuthenticationProvider中进行完成的,但是这部分内容涉及到具体的验证协议的实现逻辑非常复杂,本期就暂时略过,在一下期中我们将对验证核心最重要的组件AuthenticationProvider其依赖的组件和对应职责做一个全面的讲解。
我们下期再见。
作者:AkiraPan
链接:https://www.jianshu.com/p/e98cdf23b991
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。