SpringSecurity________UsernamePasswordAuthenticationFilter

真诚的感谢作者:本文来源https://www.jianshu.com/p/e98cdf23b991

本期任务清单

1. 了解UsernamePasswordAuthenticationFilter的职责和实现

UsernamePasswordAuthticationFilter类说明

UsernamePasswordAuthticationFilter 是AbsractAuthenticationProcessonFilter针对使用用户名和密码进行身份验证而定制化的一个过滤器。

在一开始我们我们先通过下面的配图来回忆以下我们的老朋友AbstractAuthticationProcessingFilter在框架中的角色是和职责

 AbstractAuthencationProcessiongFilter的人生

                    

 

 AbstractAuthenticationProcessinigFilter在整个身份验证的流程中主要的处理工作就是所有与Web资源相关的事情,并且将其封装成Authenticaton对象,最后调用AuthenticationManager的验证方法。所以UsernamePasswrodAuthenticationFilter的共工作大致也是如此。只不过在这个场景下更加明确了Authenticaton对象的封装数据的来源和形式-------使用用户名和密码。

接下来我们在对UsernamePasswordAuthenticationFilter的属性和方法做一个快速的了解,UsernamePasswordAuthenticationFilter 继承扩展了AbstractAuthenticationProcessiongFilter,相对AbstractAuthenticationProcessinFilter而言主要有以下几个改动

1. 属性中增加了username和password字段

2. 强制只对post请求应用。

3. 重写了attemptAuthentication身份验证的入口方法。

 

 封装用户名和密码的基石:UsernamePasswordAuthticationToken 

在UsernamePasswordAuthenticationfilter的属性生命中二外增加了username和password的冬季很容易明白。即需要从HttpRequest中获取的对应的参数字段,并将其封装进Authenticaton中,传递给AuthenticationManager进行身份验证。这里让我们回顾以下Authentication到底是什么,Authentication是一个接口生命,一个特定的行为的声明,他并不是一个类,没有办法实例化为对象进行传递,所以我们需要对Authenticaon进行实现,使其可以被实例化。

 

 在UsernamePasswordAuthticationFilter的身份验证设计里,我们需要验证协议用简单的语言可以描述为,给我一组用户名和密码,如果匹配,那么久算验证成功,用户名即是一个可以唯一标识不同用户的字段,而密码则是检验当前的身份验证是否正确的凭证。在SpringSecurity中边将使用username和password 封装成Authentication的实现生命为了

 

 usernamePasswordAuthenticationtoken继承了AbstractAuthenticationtoken抽象类,其主要与AbstractAuthenticationtoken的区别是针对用户名和密码约定进行了一定的封装,将username复制到了principal,而将password赋值到了credentials.

public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
            Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true); // must use super, as we override
    }

通过UsernamePasswordAuthenticationtoken实例化了Authentication接口,继而按照流程,将其传递给了AuthenticationManager 调用身份验证的核心完成相关的工作。

UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                username, password);

        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);

以上将来自HTTP请求中的参数按照预先的约定放入赋值给Authentication指定属性,便是UsernamePasswordAuthenticationFilter部分最主要的改动。

验证核心的工作者:AuthenticationProvider

web层的工作已经完成了,Authentication接口的实现类UsernnamePasswordAuthenticationtoken通过authenticationManager提供的方法做为参数传递到了核心验证的核心组件中。

我们曾多次强调过一个设计概念:AuthenticationManager接口设计上并不是用于完成特定的身份验证工作,。而是调用其所配发的AuthenticationProvier接口去实现的。

那么这里有一个疑问,针对接口生命参数生命的Authentication,针对不同的验证协议的AuthenticationProviderde 的实现类完成我们对应的工作。并且AuthenticationManager是如何直到哪个AuthenticationProvider需要哪个Authentication的。

哦我们首先复习以下AuthenticationProvider接口的声明

 

 AuthenticationProvider只包含两个方法声明,核心验证方法入口:

 Authentication authenticate(Authentication authentication)
            throws AuthenticationException;

另外一个便是让AuthenticationManger可以通过调用该方法分表当前AuthenticationProvider是否是完成响应验证工作的supports方法:

oolean supports(Class<?> authentication);

简单的描述便是AuthenticationProvier只提供两个方法,一个是他能不能验证当前的Authentication,还有便是让他去验证当前的Authentication.

对于Authenticationprovider整个体系能说的非常多,本期只对我们需要了解的AuthticationProvier中两个接口声明的方法做个简单的说明。其他部分以后单独对AuthticationProvider体系介绍时在做进一步召开

是否支持当前的验证协议:Boolean supports(Class<?> authentication) 

在spring Security 中唯一AuthenticationManager的实现类ProviderManager,在处理authenticate身份验证入欧方法时,首先第一个解决的问题便是:我们手下哪个AuthenticationProvider能验证当前的Authentication?为此ProviderManager便会对其所有的AuthenticationProvider做supports方法检查,正到AuthenticatonProvider能在supoorts方法被调用返回true.

 

我们了解了框架上的设计逻辑,先要直到水能处理当前的身份验证信息,在要求他进行验证工作。

 

回到我们的场景上来UsernamePasswordAuthenticationFilter已经封装好了igeUsernamePasswordAuthenticationToken传递给了providerManager.紧接着当前ProviderManager正焦头烂额的询问哪个Authenticationprovider能支持这个Authentication实现,此时的provider正如下图一样困惑

 

 在ProviderManager的视角里,所有的Authentication实现类都布局名,他不仅不能通过自身完成验证工作,也不能独立完成判断是否支持工作。而是统统交给AuthenticationProvider去完成。而不同的AuthentticationProvider开发初衷都是为了支持某种验证协议,所以在特定的AuthenticationProvider的视角中,他只关心当前Authentication是不是他预先设计处理的类型即可。

在使用用户用户名和密码的验证场景中,验证使用的用户名和密码被封装成了usernamepasswordAuthenticationtoken对象,SpringSecurity 边为了向UsernamePasswordAuthenticationToken对象在核心层提供了相关的验证服务

 

 

小结:

我们先来总结下,出现针对用户名和密码扩展过的类和其为何被扩展的原因

1. UsernamePasswordAuthenticationfilter扩展了AubstarctAuthenticationProcessionFilter,因为需要因为需要从HTTP从指定的参数中获取用户名和密码,并且传递给验证核心

2. 

  • UsernamePasswordAuthenticationToken扩展Authentication,因为我们设计了一套约定将用户名和密码放入了指定的属性中以便核心读取使用;
  • DaoAuthenticationProvider 扩展AuthenticationProvider,因为我们需要在核心中对UsernamePasswordAuthenticationToken进行处理,并按照约定读出用户名和密码使其可以进行身份验证操作。

 

 

结尾

本章的重点是介绍特定场景下框架是如何通过扩展指定组件来完成预设验证逻辑的交互过程。其实整个验证工作核心部分是在DaoAuthenticationProvider中进行完成的,但是这部分内容涉及到具体的验证协议的实现逻辑非常复杂,本期就暂时略过,在一下期中我们将对验证核心最重要的组件AuthenticationProvider其依赖的组件和对应职责做一个全面的讲解。
我们下期再见。

作者:AkiraPan
链接:https://www.jianshu.com/p/e98cdf23b991
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @ 2020-05-20 10:37  dousil  阅读(1406)  评论(0编辑  收藏  举报