Spring Security 简明教程

Spring Security - Architecture

Spring Security 是 Spring 项目或模块之一,用于保护基于 Spring 的应用程序。Spring Security 为我们在应用程序中实施身份验证和授权提供了许多内置功能。我们可以将这些功能与更改结合使用来非常快速地保护应用程序。除此之外,Spring Security 还允许大量自定义之前提到的功能,以实施我们自己的复杂身份验证和授权。

Spring Security Architecture

Spring Security 架构从 servlet 过滤器开始。这些过滤器拦截请求,对请求执行操作,然后将请求传递给过滤器链中的下一个过滤器或请求处理程序,或者如果不满足某些条件就阻止它们。在此过程中,Spring Security 可以对请求进行身份验证并对请求执行各种身份验证检查。它还可以通过不允许未经身份验证或恶意请求通过,来防止它们访问受保护的资源。因此,我们的应用程序和资源保持受保护。

components of spring security architecture

Components of Spring Security Architecture

正如我们在上图中看到的,Spring Security 的基本组件如下。我们将在进行过程中对其进行简要讨论。我们还将讨论它们在身份验证和授权过程中的作用。

正如我们在上图中看到的,Spring Security 的基本组件如下。我们将在进行过程中对其进行简要讨论。我们还将讨论它们在身份验证和授权过程中的作用。

AuthenticationFilter

这是拦截请求并尝试对其进行身份验证的过滤器。在 Spring Security 中,它将请求转换为一个 Authentication Object,并将身份验证委托给 AuthenticationManager。

AuthenticationManager

这是用于身份验证的主要策略界面。它使用单一方法 authenticate() 来对请求进行身份验证。authenticate() 方法执行身份验证,并在身份验证成功后返回一个 Authentication Object,或者在身份验证失败的情况下抛出 AuthenticationException。如果该方法无法判断,它将返回 null。此过程中的身份验证过程将委托给 AuthenticationProvider,我们将在后面讨论它。

AuthenticationProvider

AuthenticationManager 由 ProviderManager 实现,后者将进程委托给一个或多个 AuthenticationProvider 实例。实现 AuthenticationProvider 接口的任何类都必须实现两个方法——authenticate() 和 supports()。首先,让我们谈谈 supports() 方法。它用于检查我们的 AuthenticationProvider 实现类是否支持特定的身份验证类型。如果支持,则返回 true,否则返回 false。接下来是 authenticate() 方法。身份验证发生在这里。如果支持身份验证类型,则开始身份验证进程。在这里,此类可以使用 UserDetailsService 实现的 loadUserByUsername() 方法。如果找不到用户,它可能会抛出 UsernameNotFoundException。

另一方面,如果找到了用户,那么会使用用户的认证详细信息来对用户进行认证。例如,在基本认证方案中,可能会使用数据库中的密码来检查用户提供的密码。如果发现它们彼此匹配,则是一个成功场景。然后,我们可以从方法中返回一个认证对象,该对象将存储在安全上下文中,我们将在后面讨论安全上下文。

UserDetailsService

它是 Spring Security 的核心接口之一。任何请求的认证主要取决于 UserDetailsService 接口的实现。它最常用于基于数据库的认证中以检索用户数据。数据通过实现唯一的 loadUserByUsername() 方法来检索,在该方法中,我们可以提供逻辑以获取用户的用户详细信息。如果找不到用户,该方法将抛出 UsernameNotFoundException。

PasswordEncoder

在 Spring Security 4 之前,使用 PasswordEncoder 是可选的。用户可以使用基于内存的认证来存储明文密码。但是 Spring Security 5 强制要求使用 PasswordEncoder 来存储密码。这会使用其许多实现之一对用户的密码进行编码。其最常见的实现是 BCryptPasswordEncoder。此外,出于开发目的,我们可以使用 NoOpPasswordEncoder 的一个实例。它将允许密码以明文存储。但它不应该用于生产或实际应用程序。

Spring Security Context

这是在成功认证时存储当前已认证用户详细信息的位置。然后,整个应用程序在会话期间都可以使用认证对象。因此,如果我们需要用户名或任何其他用户详细信息,则需要首先获得 SecurityContext。这是通过 SecurityContextHolder 一个提供程序类来完成的,它提供对安全上下文的访问。我们可以分别使用 setAuthentication() 和 getAuthentication() 方法来存储和检索用户详细信息。

继续,现在让我们讨论我们将用于我们应用程序的三个自定义实现。

Form Login

当我们将 Spring Security 添加到现有的 Spring 应用程序时,它会添加一个登录表单并设置一个虚拟用户。这是自动配置模式下的 Spring Security。在此模式下,它还设置了默认过滤器、身份验证管理器、身份验证提供程序等。此设置是内存中身份验证设置。我们可以覆盖此自动配置以设置我们自己的用户和身份验证流程。我们还可以设置我们自定义的登录方法,例如自定义登录表单。Spring Security 仅需要了解登录表单的详细信息,如 - 登录表单的 URI、登录处理 URL 等。然后,它将为应用程序呈现我们的登录表单,并执行身份验证过程以及其他提供的配置或 Spring 自己的实现。

若要将自定义表单设置集成到 Spring Security 中,只需遵守特定的规则即可。我们需要一个用户名参数和一个密码参数,并且这两个参数的名称应分别为“username”和“password”,因为这是默认的名称。在此自定义设置中,如果我们为这些字段使用自己的参数名称,则必须使用 usernameParameter() 和 passwordParameter() 方法通知 Spring Security 这些更改。同样,对于我们对登录表单或表单登录方法所做的任何更改,我们都必须使用适当的方法通知 Spring Security 这些更改,以便它可以将这些更改集成到认证流程中。