认证篇:Spring Security 表单登录认证源码解析

本文深入解析Spring Security的表单登录认证过程,包括登录信息封装、认证流程及关键类的作用。通过分析源码,了解认证管理接口、认证管理类以及具体认证处理器的工作原理,为自定义认证方式打下基础。
摘要由CSDN通过智能技术生成

图1-0 表单登录源码解析总结图

原理讲解

接上回分解,上回我们聊到了认证(一):基于表单登录的认证模式,正所谓:“知其然,然后知其所以然”;就让我们来一探究竟,瞅瞅 Spring Security到底是怎么实现表单登录的。

首先我们先来回顾一下上篇文章我们制作的 Spring Security的表单认证的流程图:

图1-1 Spring Security表单登录认证流程图

从流程图中我们可以简单的了解到,整个认证流程大致上分为3个模块:

  • 登录信息的封装

  • 认证

  • 收尾处理(成功&失败处理)

核心模块为 认证模块,下面就来看看认证模块 AuthenticationManager的相关类图:

图1-2 认证类图

该图可以分2块来看,分别是左边负责掌控全局的"大哥",以及右边勤勤恳恳的"小弟们"。

总所周知,“大哥"都不需要亲历亲为的,所以"大哥” AuthenticationManager认证管理接口,只定义了认证方法 authenticate(),具体咋实现就让小弟们去搞吧~~

“二当家” ProviderManager为认证管理类,实现了 AuthenticationManager(二当家肯定要听大哥的话),并在认证方法 authenticate()中将身份认证委托给具有认证资格的 AuthenticationProvider(真正干活的小弟们);同时
ProviderManaer有一个成员变量 List<AuthenticationProvider> providers用以存储了所有具体执行认证的"小弟们"。

接下来介绍一下右边勤勤恳恳的"小弟们",首先是AuthenticationProvider认证接口类,其定义了身份认证方法authenticate();这个也比较好理解;你怎么证明自己是我的"小弟"呢?当然是得入我门为我干活拉!AuthenticationProvider接口就是起这个作用。

AbstractUserDetailAuthenticationProvider为认证抽象类,实现了接口AuthenticationProvider,同时还定义了抽象方法retrieveUser()用于从数据库中获取用户信息,以及additionalAuthenticationChecks()做身份认证;这块可能会犯迷糊,为啥子这个"小弟"还是个抽象类呢?不必慌张,其实只是为了一些功能的复用。

DaoAuthenticationProvider认证类继承于AbstractUserDetailAuthenticationProvider抽象认证类,实现了上面提到的2个抽象方法retrieveUser和additionalAuthenticationChecks;并自定义了一些成员变量:private UserDetailsService userDetailsService;用以用户信息查询,以及private PasswordEncoder passwordEncoder用作密码的加密认证。

源码解析

在大致了解了原理之后,就开始了我们的阅读源码之旅拉;分两个模块来看,分别是:登录信息的封装以及 认证

登录信息的封装

登录信息的封装是指将前端传递的username和password封装成 UsernamePasswordAuthenticationToken

UsernamePasswordAuthenticationFilter.class的 attemptAuthentication()方法

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
   
    if (this.postOnly && !request.getMethod().equals("POST")) {
   
        throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
    } else {
   
        String username = this.obtainUsername(request);
        String password = this.obtainPassword(request);
        if (username == null) {
   
            username = "";
        }

        if (password == null) {
   
            password = "";
        }

        username = username.trim();
        // 将http请求的Request带的认证参数:username、password转换为认证的token对象
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        // 设置一些详细信息, 诸如发送请求的ip等...
        this.setDetails(request, authRequest);
        // 调用AuthenticationManager的authenticate方法 执行认证
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

attemptAuthentication()方法做的事情很简单,主要是将登录信息 username和password封装成 UsernamePasswordAuthenticationToken。那么这个Token到底是起什么作用呢?其实也很简单,主要是用于后续认证的时候,寻找匹配的认证处理器,例如表单登录的 UsernamePasswordAuthenticationToken会唯一匹配相应的认证Provider

认证

从上面我们也可以看到,在将登录信息封装成Token后,就调用了 AuthenticationManagerauthenticate()方法执行认证操作;因 AuthenticationManager是一个接口,我们来分析它的实现类 ProviderManager

ProviderManager.class的authenticate()方法

public Authentication authenticate(Authentication authen
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值