spring security文档阅读

This commit is contained in:
asahi
2024-03-15 00:21:59 +08:00
parent e593bfaa81
commit 6c0404485c

View File

@@ -1,3 +1,48 @@
- [Spring Security](#spring-security)
- [Spring Security简介](#spring-security简介)
- [Spring Security自动配置](#spring-security自动配置)
- [Spring Security结构](#spring-security结构)
- [DelegatingFilterProxy](#delegatingfilterproxy)
- [FilterChainProxy](#filterchainproxy)
- [SecurityFilterChain](#securityfilterchain)
- [SecurityFilters](#securityfilters)
- [添加自定义filter到SecurityFilterChain](#添加自定义filter到securityfilterchain)
- [处理Security异常](#处理security异常)
- [在多次认证之间保存request](#在多次认证之间保存request)
- [RequestCache](#requestcache)
- [Spring Security身份认证的结构](#spring-security身份认证的结构)
- [SecurityContextHolder](#securitycontextholder)
- [SecurityContext](#securitycontext)
- [Authentication](#authentication)
- [GrantedAuthority](#grantedauthority)
- [AuthenticationManager](#authenticationmanager)
- [ProviderManager](#providermanager)
- [AuthenticationProvider](#authenticationprovider)
- [AuthenticationEntryPoint](#authenticationentrypoint)
- [AbstractAuthenticationProcessingFilter](#abstractauthenticationprocessingfilter)
- [认证流程](#认证流程)
- [用户名/密码认证](#用户名密码认证)
- [Form Login](#form-login)
- [用户被重定向到登录页面的过程](#用户被重定向到登录页面的过程)
- [认证用户名和密码过程](#认证用户名和密码过程)
- [基本Authentication](#基本authentication)
- [基本Authentication的认证流程](#基本authentication的认证流程)
- [Digest Authentication(摘要认证,***不安全***)](#digest-authentication摘要认证不安全)
- [摘要认证中的随机数](#摘要认证中的随机数)
- [密码存储方式](#密码存储方式)
- [内存中存储密码](#内存中存储密码)
- [内存中存储密码时使用defaultPasswordEncoder](#内存中存储密码时使用defaultpasswordencoder)
- [JDBC Authentication](#jdbc-authentication)
- [User Schema](#user--schema)
- [Group Schema](#group-schema)
- [配置Datasource](#配置datasource)
- [创建JdbcUserDetailsManager Bean对象](#创建jdbcuserdetailsmanager-bean对象)
- [UserDetails](#userdetails)
- [UserDetailsService](#userdetailsservice)
- [PasswordEncoder](#passwordencoder)
- [DaoAuthenticationProvider](#daoauthenticationprovider)
# Spring Security # Spring Security
## Spring Security简介 ## Spring Security简介
Spring Security作为一个安全框架向使用者提供了用户认证、授权、常规攻击保护等功能。 Spring Security作为一个安全框架向使用者提供了用户认证、授权、常规攻击保护等功能。
@@ -29,15 +74,83 @@ Spring Security支持FilterChainProxyFilterChainProxy是一个由Spring Secur
***FilterChainProxy是一个bean对象通过被包含在DelegatingFilterProxy中。*** ***FilterChainProxy是一个bean对象通过被包含在DelegatingFilterProxy中。***
### SecurityFilterChain ### SecurityFilterChain
SecurityFilterChain通常被FilterChainProxy使用用来决定在该次请求中调用那些Spring Security Filters。 SecurityFilterChain通常被FilterChainProxy使用用来决定在该次请求中调用哪个Spring Security Filters。
### SecurityFilters ### SecurityFilters
Security Filters通过SecurityFilterChain API被插入到FilterChainProxy中。 Security Filters通过SecurityFilterChain API被插入到FilterChainProxy中。
### 添加自定义filter到SecurityFilterChain
大多数情况下默认的security是足够的但是也允许向security filter chain中添加自定义过滤器。
如下是一个自定义过滤器的示例示例中自定义filter会在认证后校验用户对于请求的租户是否拥有权限
```java
import java.io.IOException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
public class TenantFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String tenantId = request.getHeader("X-Tenant-Id"); //(1)
boolean hasAccess = isUserAllowed(tenantId); //(2)
if (hasAccess) {
filterChain.doFilter(request, response); //(3)
return;
}
throw new AccessDeniedException("Access denied"); //(4)
}
}
```
如下是自定义过滤器链的流程:
1. 步骤从请求header中获取了tenantId
2. 步骤校验了用户对于该tenant id代表的租户资源是否拥有访问权限
3. 只有当用户对租户资源拥有访问权限时才会继续调用filterChain中剩余的部分
4. 如果用户没有访问权限将会抛出AccessDeniedException
在定义完自定义过滤器后还需要将自定义filter添加到Security Filter Chain中添加代码如下所示例
```java
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.addFilterBefore(new TenantFilter(), AuthorizationFilter.class);
return http.build();
}
```
> 由于权限校验操作在身份认证之后故而将TenantFilter加到AuthorizationFilter之前可以保证在执行TenantFilter时所有的身份认证操作都已经执行完成。
> 在向SecurityFilterChain注册filter时不应该将自定义filter注册为bean因为spring会将注册为bean的filter对象都添加到内置容器中这会造成注册为bean的filter被调用两次一次被Spring Seurity调用一次被container调用。
### 处理Security异常 ### 处理Security异常
ExceptionTranslationFilter将认证异常和权限异常翻译为http response。 ExceptionTranslationFilter将`AccessDeniedException``AuthenticationException`翻译为http response。
> ExceptionTranslationFilter被插入到FilterChainProxy中作为SecurityFilterChain中的一个。
> ExceptionTranslationFilter被插入到FilterChainProxy中作为SecurityFilterChain中的一个filter。
> 如果应用程序没有抛出AccessDeniedException或AuthenticationException那么ExceptionTranslationFilter并不会做任何事情。 > 如果应用程序没有抛出AccessDeniedException或AuthenticationException那么ExceptionTranslationFilter并不会做任何事情。
ExceptionTranslationFilter的处理流程
1. ExceptionTranslationFilter首先会调用`filterChain.doFilter`来执行后续的逻辑
2. 在执行后续请求时如果抛出了AuthenticationException那么则会开启认证流程
1. 清空SecurityContextHolder
2. 保存HttpServletRequest当认证通过时还能重新发送原始请求
3. `AuthenticationEntryPoint`用于重新请求用户的凭证,其可能会重定向到登录页面或是发送 `www-authenticate`header
3. 在执行后续请求时如果抛出了AccessDeniedException那么会调用`AccessDeniedHandler`用于处理访问拒绝。
4. 如果执行后续逻辑时,抛出了非`AuthenticationException``AccessDeniedException`的异常那么异常将会被重新抛出ExceptionTranslationFilter并不会针对其进行处理
```java ```java
// ExceptionTranslationFilter的伪代码 // ExceptionTranslationFilter的伪代码
try { try {
@@ -51,6 +164,46 @@ try {
} }
``` ```
### 在多次认证之间保存request
如果用户在发送请求访问需要认证的资源时尚未经过身份认证那么需要将本次请求保存起来并且对用户进行认证待用户认证通过之后再重新执行保存的原始请求。在Spring Security中是通过RequestCache来实现保存请求的。
#### RequestCache
HttpServletRequest被保存在RequestCache中当用户经过重新认证后RequestCache将会用于重新发送原始请求。
在Spring Security中在sendStartAuthentication时会像requestCache中存储request并且重新执行认证流程认证通过后将会重新发送原始请求。
RequestCacheAwareFilter负责请求的重新发送。
默认情况下,会使用`HttpSessionRequestCache`如下代码展示了HttpSessionRequestCache的自定义使用
```java
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
// 匹配本次request时需要确保请求url参数中具有continue参数
requestCache.setMatchingRequestParameterName("continue");
http
// ...
.requestCache((cache) -> cache
.requestCache(requestCache)
);
return http.build();
}
```
由于在认证失败时存储原始请求会占用内存如果想要禁止在抛出AuthenticationException后保存原始请求到RequestCache的行为可以为SecurityFilterChain指定`NullRequestCache`
```java
@Bean
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
RequestCache nullRequestCache = new NullRequestCache();
http
// ...
.requestCache((cache) -> cache
.requestCache(nullRequestCache)
);
return http.build();
}
```
## Spring Security身份认证的结构 ## Spring Security身份认证的结构
### SecurityContextHolder ### SecurityContextHolder
Spring Security身份认证的核心模型SecurityContextHolder包含有SecurityContext。 Spring Security身份认证的核心模型SecurityContextHolder包含有SecurityContext。