Spring-Security登录验证流程源码解析

42次阅读

共计 1873 个字符,预计需要花费 5 分钟才能阅读完成。

一、登录认证基于过滤器链

Spring Security 的登录验证流程核心就是过滤器链。当一个请求到达时按照过滤器链的顺序依次进行处理,通过所有过滤器链的验证,就可以访问 API 接口了。

SpringSecurity 提供了多种登录认证的方式,由多种 Filter 过滤器来实现,比如:

  • BasicAuthenticationFilter 实现的是 HttpBasic 模式的登录认证
  • UsernamePasswordAuthenticationFilter 实现用户名密码的登录认证
  • RememberMeAuthenticationFilter 实现登录认证的“记住我”的功能
  • SmsCodeAuthenticationFilter 实现短信验证码登录认证
  • SocialAuthenticationFilter 实现社交媒体方式登录认证的处理
  • Oauth2AuthenticationProcessingFilter 和 Oauth2ClientAuthenticationProcessingFilter 实现 Oauth2 的鉴权方式

根据我们不同的需求实现及配置,不同的 Filter 会被加载到应用中。

二、结合源码讲解登录验证流程

我们就以用户名、密码登录方式为例讲解一下 Spring Security 的登录认证流程。

2.1 UsernamePasswordAuthenticationFilter

该过滤器封装用户基本信息(用户名、密码),定义登录表单数据接收相关的信息。如:

  • 默认的表单用户名密码 input 框 name 是 username、password
  • 默认的处理登录请求路径是 /login、使用 POST 方法


2.2 AbstractAuthenticationProcessingFilter 的 doFilter 方法的验证过程

UsernamePasswordAuthenticationFilter 继承自抽象类 AbstractAuthenticationProcessingFilter,该抽象类定义了验证成功与验证失败的处理方法。

2.3 验证成功之后的 Handler 和验证失败之后的 handler

也就是说当我们需要自定义验证成功或失败的处理方法时,要去实现 AuthenticationSuccessHandler 或 AuthenticationfailureHandler 接口

三、登录验证内部细节

3.1 多种认证方式的管理 ProviderManager

ProviderManager 用继承于 AuthenticationManager 是登录验证的核心类。ProviderManager 保管了多个 AuthenticationProvider,用于不同类型的登录验证。比如:

  • RememberMeAuthenticationProvider 定义了“记住我”功能的登录验证逻辑
  • DaoAuthenticationProvider 加载数据库用户信息,进行用户密码的登录验证
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
    ……
    private List<AuthenticationProvider> providers;
    ……

下文是 ProviderManager 的核心源码,遍历不同登录验证的 AuthenticationProvider,只有当这种方式被支持的时候,才执行具体的登录验证逻辑。

3.2 登录认证接口 AuthenticationProvider

public interface AuthenticationProvider {Authentication authenticate(Authentication var1) throws AuthenticationException;

    boolean supports(Class<?> var1);
}

AuthenticationProvider 的实现类定义了具体的登录验证逻辑

3.3 数据库加载用户信息 DaoAuthenticationProvider

public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

从数据库获取用户信息源码

所以当我们需要加载用户信息进行登录验证的时候,我们需要实现 UserDetailsService 接口,重写 loadUserByUsername 方法,参数是用户输入的用户名。返回值是UserDetails

正文完
 0