查看原文
其他

深入理解Spring Security认证流程

学研妹 Java学研大本营 2024-01-02

介绍 Spring Security 框架及身份验证流程的相关组件,为使用和自定义 Spring Security 提供帮助。

长按关注《Java学研大本营》

Spring Security 是一个功能强大的框架,用于保护 Spring 应用程序。它专注于身份验证和授权,并可根据需求进行配置和自定义。本文将讨论用于身份验证的不同组件,在实际应用中,了解身份验证组件的概念对于使用 Spring Security 进行实现和自定义非常有帮助。

1 没有使用 Spring Security

如果我们没有使用 Spring Security,那么请求将被 DispatcherServlet 拦截。DispatcherServlet 是前端控制器,它拦截任何 HTTP 请求并将其转发到正确的控制器。在 Spring Boot 中,DispatcherServlet 会被自动配置。

请求会被 DispatcherServlet 拦截

2 DispatcherServlet 是如何工作的

在深入了解 Spring Security 之前,让我们先了解一下 DispatcherServlet 如何分发请求。当我们在一个端点(比如 /helloworld)发出请求时,前端控制器(DispatcherServlet)会如何处理它?

DispatcherServlet 创建了一个 IOC 容器,它是 Spring Framework 的核心组件之一,用于管理 bean 的创建和依赖关系。DispatcherServlet 创建的是 WebApplicationContext,这是一个专门用于 Web 应用程序的 IOC 容器。WebApplicationContext 是根据配置文件由 DispatcherServlet 进行配置的。

IOC 容器会创建控制器 bean 的实例。当请求到达时,DispatcherServlet 会使用 IOC 容器查找适当的控制器 bean,并委托给它来处理请求。

3 使用 Spring Security

当将 Spring Security 添加到 Spring Boot 应用程序中时,所有请求在到达 DispatcherServlet 和控制器之前都会被 Spring Security 机制拦截。

每当一个请求到达应用程序时,它首先被一系列过滤器拦截,这些过滤器称为 Filter Chain。除了 Spring Security 提供的过滤器之外,我们还可以添加自己的自定义过滤器。认证后的 FilterChain 将请求转发到 DisptacherServlet。

过滤器链拦截传入请求

4 认证流程:步骤

身份验证请求和响应

虽然 Spring Security 可以与不同类型的身份验证方法一起使用,但在本文中,我们讨论的是用户名和密码身份验证,以便深入了解完整的身份验证流程。

  • Filter Chain 在将请求转发给 Dispatcher Servlet 之前拦截传入请求。
  • 请求进入认证过滤器(其中一个过滤器是 UsernamePasswordAuthenticationFilter)。
  • 过滤器从请求(HttpServletRequest 对象)中提取用户名和密码。
  • 然后使用凭据创建 UsernamePasswordAuthenticationToken。
  • 调用 AuthenticationManager 的 authenticate() 方法。
  • AuthenticationManager 的 authenticate() 方法实现将尝试使用其拥有的 AuthenticationProvider 之一进行身份验证。
  • 如果一个身份验证提供程序能够成功进行身份验证,它将返回一个包含凭据和权限的完整的 UsernamePasswordAuthenticationToken。
  • 提供程序返回的此令牌用于在 Spring Security 上下文中将用户设置为已认证。
  • 一旦用户通过身份验证,请求就会被转发到处理请求的 DispatcherServlet。

5 身份验证流程的不同组件

我们了解一下前面部分讨论的不同组件。

5.1 什么是过滤器

Spring Filter 是一个组件,可以拦截任何传入请求,并在将其传递给 DispatcherServlet 之前执行某些操作。过滤器可以处理请求,然后将其转发到 Filter Chain 中的下一个过滤器,或者可以停止并发送回 HTTP 响应。其中一个过滤器是存在于 FilterChain 中的 UsernamePasswordAuthenticationFilter。此过滤器尝试查找 HTTP Post 请求中传递的用户名和密码,如果找到,则尝试使用凭据对用户进行身份验证。以下是此类中存在的身份验证方法的快照。

我们可以创建自己的 Filter 并将其添加到 SecurityFilterChain 中,以提供自己的逻辑来处理请求。

5.2 什么是 AuthenticationManager

AuthenticationManager 是一个接口,用于处理身份验证的过程。它只有一个方法 authenticate(Authentication authentication),该方法将一个身份验证对象作为参数,并返回已经认证的身份验证对象。身份验证对象通常是一个包含用户名和密码等凭据的 AuthenticationToken 对象。

Authentication authenticate(Authentication authentication) throws AuthenticationException;

AuthenticationManager 的实现类是 ProviderManager 类,它提供了 authenticate() 方法的逻辑。我们可以提供我们自己的 AuthenticationProvider 实现类或使用默认实现。

5.3 什么是 ProviderManager

该类实现了 AuthenticationManager 接口并覆盖了 authenticate() 方法。它使用一组 AuthenticationProvider 来验证 Authentication 对象中发送的凭据。如果 AuthenticationProvider 支持身份验证类型,则将用于验证用户。如果没有提供者支持身份验证类型,则将抛出 AuthenticationException。

每个身份验证提供程序的 supports() 方法用于检查它是否可以支持所需的身份验证类型。

5.4 什么是 AuthenticationProvider

AuthenticationProvider 是一个接口,用于定义验证用户的协议。它负责接收 Authentication 对象(表示用户凭据)并返回已经认证的 Authentication 对象,如果凭据有效。如果凭据无效,则 AuthenticationProvider 应该抛出 AuthenticationException。

AuthenticationProvider 接口有两个方法:

  • authenticate():此方法接受 Authentication 对象作为输入,并在凭据有效时返回已认证的 Authentication 对象。如果凭据无效,则 AuthenticationProvider 应该抛出 AuthenticationException。
  • supports():此方法接受 Authentication 对象作为输入,并且如果 AuthenticationProvider 可以验证该对象,则返回 true。如果 AuthenticationProvider 无法验证该对象,则应返回 false。

Spring Security 中的默认 AuthenticationProvider 是 DaoAuthenticationProvider。此提供程序使用 UserDetailsService 从数据库加载用户详细信息。如果用户凭据与数据库中的详细信息匹配,则 DaoAuthenticationProvider 将返回已经认证的 Authentication 对象。

我们可以添加我们自己的 AuthenticationProvider 实现来提供不同的身份验证方法。

5.5 身份验证和 UsernamePasswordAuthenticationToken

Authentication 和 UsernamePasswordAuthenticationToken 是什么?

  • Authentication

这是 Spring Security 中的一个接口,表示传入身份验证请求的令牌或已认证的主体(表示一个实体,比如个人)AuthenticationManager.authenticate() 方法。

提供的一些方法为:

Collection<? extends GrantedAuthority> getAuthorities();
 Object getCredentials();
 boolean isAuthenticated();
 void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
  • UsernamePasswordAuthenticationToken

此类扩展了 AbstractAuthenticationToken 类(身份验证对象的基类),可用于用户名/密码身份验证请求。

此类有两个构造函数:

public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
    super((Collection)null);
    this.principal = principal;
    this.credentials = credentials;
    this.setAuthenticated(false);
}

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

第一个构造函数可用于传入请求以创建未经身份验证的 Authentication 对象。

Authentication authentication = new UsernamePasswordAuthenticationToken(username,password);

第二个构造函数可用于创建完全经过身份验证的 Authentication 对象。

Authentication authToken = new UsernamePasswordAuthenticationToken(username, password, userAuthorities);

然后,此完全经过身份验证的 Authentication 对象从 AuthenticationProvider/AuthenticationManager 返回并表示已认证的用户。然后将此已认证的对象设置在 SecurityContext 中。Spring Security 中的 SecurityContext 是当前执行线程的安全上下文的表示。它包含有关当前已认证用户的信息,例如其用户名、权限和会话信息。

6 总结

本文提供了身份验证流程的简要描述,以及设置身份验证所需的不同组件。任何想要使用 Spring Security 的人在进行更多自定义和实现之前,必须清楚了解这些概念。

推荐书单

《名师讲坛——Spring实战开发(Redis+SpringDataJPA+SpringMVC+SpringSecurity)》

Spring是当今Java开发行业之中的主流技术开源框架,利用Spring框架中IOC&DI与AOP实现机制可以轻松地实现轻量级的Java企业级项目开发。同时简单的代码开发形式与灵活的配置,可以极大地降低开发人员的代码编写难度。基于Spring还可以轻松整合许多Java的标准服务与第三方开发框架,使得项目的开发有良好的规范性。

《名师讲坛:Spring实战开发(Redis+SpringDataJPA+SpringMVC+SpringSecurity)》一共分为15章,核心的内容包括Spring框架结构、IOC&DI、AOP、Bean管理、资源管理、表达式语言和定时调度,同时整合了JMS消息服务、Web服务、Redis数据库、JDBC和JPA等服务组件,最后又讲解了流行的SpringMVC以及Spring提供的授权管理组件SpringSecurity。

《名师讲坛:Spring实战开发(Redis+SpringDataJPA+SpringMVC+SpringSecurity)》适用于从事Java开发的技术工程师,也适用于Java技术爱好者,同时也可以作为应用型高等院校及培训机构的学习教材。

购买链接:https://item.jd.com/12793838.html

精彩回顾

2023年最新的10个高效Android Studio和IntelliJ IDEA插件

使用连接池优化Spring Boot性能

不可不知的IntelliJ IDEA使用小技巧(下)

不可不知的IntelliJ IDEA使用小技巧(上)

手把手教你将Java代码转换为Kotlin

长按关注《Java学研大本营》
长按访问【IT今日热榜】,发现每日技术热点
继续滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存