【Spring】Spring Security 核心类介绍及Spring Security 的验证机制

发布于:2024-07-02 ⋅ 阅读:(25) ⋅ 点赞:(0)

一、Spring Security 核心类

Spring Security 核心类包括 AuthenticationSecurityContextHolderUserDetailsUserDetailsServiceGrantedAuthorityDaoAuthenticationProviderPasswordEncoder

1.1 Authentication

Authentication 用来表示用户认证信息,在用户登录认证之前,Spring Security 会将相关信息封装为一个 Authentication 具体实现类的对象,在登录认证成功之后又会生成一个信息更全面、包含用户权限等信息的 Authentication 对象,然后把它保存在 SecurityContextHolder 所持有的 SecurityContext 中,供后续的程序进行调用,如访问权限的鉴定等。

1.2 SecurityContextHolder

SecurityContextHolder 是用来保存 SecurityContext 的。 SecurityContext 中含有当前所访问系统的用户的详细信息。默认情况下, SecurityContextHolder 将使用 ThreadLocal 来保存 SecurityContext,这也就意味着在处于同一线程的方法中,可以从 ThreadLocal 获取到当前的 SecurityContext。

Spring Security 使用一个 Authentication 对象来描述当前用户的相关信息。SecurityContextHolder 中持有的是当前用户的 SecurityContext,而 SecurityContext 持有的是代表当前用户相关信息的 Authentication 的引用。这个 Authentication 对象不需要我们自己创建,在与系统交互的过程中, Spring Security 会自动创建相应的 Authentication 对象,然后赋值给当前的 SecurityContext。开发过程中常常需要在程序中获取当前用户的相关信息,比如最常见的是获取当前登录用户的用户名。

示例代码如下:

String username = SecurityContextHolder.getContext().getAuthentication().getName();

1.3 UserDetails

UserDetails 是 Spring Security 的一个核心接口。其中定义了一些可以获取用户名、密码、权限等与认证相关的信息的方法。Spring Security 内部使用的 UserDetails 实现类大都是内置的 User 类,要使用 UserDetails,也可以直接使用该类。在 Spring Security 内部,很多需要使用用户信息的时候,基本上都是使用 UserDetails,比如在登录认证的时候。

通常需要在应用中获取当前用户的其他信息,如E-mail、电话等。这时存放在 Authentication 中的 principal 只包含认证相关信息的 UserDetails 对象可能就不能满足我们的要求了。这时可以实现的 UserDetails,在该实现类中可以定义一些获取用户其他信息的方法,这样将来就可以直接从当前 SecurityContext 的 Authentication 的 principal 中获取这些信息。

UserDetails 是通过 UserDetailsService 的 loadUserByUsername() 方法进行加载的。 UserDetailsService 也是一个接口,我们也需要实现自己的 UserDetailsService 来加载自定义的 UserDetails 信息。

1.4 UserDetailsService

Authentication.getPrincipal() 的返回类型是 Object,但很多情况下返回的其实是一个 UserDetails 的实例。登录认证的时候 Spring Security 会通过 UserDetailsService 的 loadUserByUsername() 方法获取对应的 UserDetails 进行认证,认证通过后会将该 UserDetails 赋给认证通过的 Authentication 的 principal,然后再把该 Authentication 存入 SecurityContext。之后如果需要使用用户信息,可以通过 SecurityContextHolder 获取存放在 SecurityContext 中的 Authentication 的 principal。

1.5 GrantedAuthority

Authentication 的 getAuthorities() 可以返回当前 Authentication 对象拥有的权限,即当前用户拥有的权限。其返回值是一个 GrantedAuthority 类型的数组,每一个 GrantedAuthority 对象代表赋予给当前用户的一种权限。GrantedAuthority 是一个接口,其通常是通过 UserDetailsService 进行加载,然后赋予 UserDetails 的。

GrantedAuthority 中只定义了一个 getAuthority()方法,该方法返回一个字符串,表示对应的权限,如果对应的权限不能用字符串表示,则应当返回 null。

1.6 DaoAuthenticationProvider

Spring Security 默认会使用 DaoAuthenticationProvider 实现 AuthenticationProvider 接口,专门进行用户认证的处理。 DaoAuthenticationProvider 在进行认证的时候需要一个 UserDetailsService 来获取用户的信息 UserDetails,其中包括用户名、密码和所拥有的权限等。如果需要改变认证的方式,开发者可以实现自己的 AuthenticationProvider。

1.7 PasswordEncoder

在 Spring Security 中,对密码的加密都是由 PasswordEncoder 来完成的。在 Spring Security 中,已经对 PasswordEncoder 有了很多实现,包括 md5 加密、SHA-256 加密等,开发者只要直接拿来用就可以。在 DaoAuthenticationProvider 中,有一个就是 PasswordEncoder 属性,密码加密功能主要靠它来完成。
在 Spring 的官方文档中明确指出,如果开发一个新的项目,BCryptPasswordEncoder 是较好的选择。BCryptPasswordEncoder 使用 BCrypt 的强散列哈希加密实现,并可以由客户端指定加密的强度,强度越高安全性自然就越高。

二、 Spring Security 的验证机制

Spring Security 大体上是由一堆 Filter 实现的,Filter 会在 SpringMVC 前拦截请求。 Filter 包括登出 Filter(LogoutFilter)、用户名密码验证 Filter(UsernamePasswordAuthenticationFilter)之类。Filter 再交由其他组件完成细分的功能,最常见的 UsernamePasswordAuthenticationFilter 会持有一个 AuthenticationManager 引用,AuthenticationManager 是一个验证管理器,专门负责验证。但是 AuthenticationManager 本身并不做具体的验证工作,AuthenticationManager 持有一个 AuthenticationProvider 集合,AuthenticationProvider 才是做验证工作的组件,验证成功或失败之后调用对应的 Handler。


本文完结!