post:完成Spring Security基础文章。
This commit is contained in:
parent
fffdd03333
commit
c30c88dfbd
130
drawings/spring-secrutiy-authentication-manager.puml
Normal file
130
drawings/spring-secrutiy-authentication-manager.puml
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
@startuml
|
||||||
|
skinparam Shadowing false
|
||||||
|
skinparam class {
|
||||||
|
BackgroundColor White
|
||||||
|
}
|
||||||
|
hide empty members
|
||||||
|
|
||||||
|
interface AuthenticationManager {
|
||||||
|
+ Authentication authenticate(Authentication authentication)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProviderManager {
|
||||||
|
- AuthenticationEventPublisher eventPublisher
|
||||||
|
- List<AuthenticationProvider> providers
|
||||||
|
- MessageSourceAccessor messages
|
||||||
|
- AuthenticationManager parent
|
||||||
|
- boolean eraseCredentialsAfterAuthentication
|
||||||
|
+ ProviderManager(AuthenticationProvider... providers)
|
||||||
|
+ ProviderManager(List<AuthenticationProvider> providers)
|
||||||
|
+ ProviderManager(List<AuthenticationProvider> providers, AuthenticationManager parent)
|
||||||
|
+ void afterPropertiesSet()
|
||||||
|
- void checkState()
|
||||||
|
- void copyDetails(Authentication source, Authentication dest)
|
||||||
|
+ List<AuthenticationProvider> getProviders()
|
||||||
|
+ void setMessageSource(MessageSource messageSource)
|
||||||
|
+ void setAuthenticationEventPublisher(AuthenticationEventPublisher eventPublisher)
|
||||||
|
+ void setEraeseCredentialsAfterAuthentication(boolean eraseSecretData)
|
||||||
|
+ boolean isEraseCredentialsAfterAuthentication()
|
||||||
|
}
|
||||||
|
|
||||||
|
class NullEventPublisher
|
||||||
|
|
||||||
|
interface AuthenticationEventPublisher {
|
||||||
|
+ void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication)
|
||||||
|
+ void publishAuthenticationSuccess(Authentication authentication)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AuthenticationProvider {
|
||||||
|
+ Authentication authenticate(Authentication authentication)
|
||||||
|
+ boolean supports(Class<?> authentication)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract AbstractUserDetailsAuthenticationProvider {
|
||||||
|
# MessageSourceAccessor messages
|
||||||
|
- UserCache userCache
|
||||||
|
- boolean forcePrincipalAsString
|
||||||
|
- boolean hideUserNotFoundException
|
||||||
|
- UserDetailsChecker preAuthenticationChecks
|
||||||
|
- UserDetailsChecker postAuthenticationChecks
|
||||||
|
- GrantedAuthoritiesMapper authoritiesMapper
|
||||||
|
#{abstract} void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
|
||||||
|
+ void afterPropertiesSet()
|
||||||
|
- String determineUsername(Authentication authentication)
|
||||||
|
# Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user)
|
||||||
|
# void doAfterPropertiesSet()
|
||||||
|
#{abstract} UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserDetailsChecker {
|
||||||
|
+ void check(UserDetails toCheck)
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultPreAuthenticationChecks
|
||||||
|
class DefaultPostAuthenticationChecks
|
||||||
|
|
||||||
|
interface UserCache {
|
||||||
|
+ UserDetails getUserFromCache(String username)
|
||||||
|
+ void putUserInCache(UserDetails user)
|
||||||
|
+ void removeUserFromCache(String username)
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserDetails {
|
||||||
|
+ Collection<? extends GrantedAuthority> getAuthorities()
|
||||||
|
+ String getPassword()
|
||||||
|
+ String getUsername()
|
||||||
|
+ boolean isAccountNonExpired()
|
||||||
|
+ boolean isAccountNonLocked()
|
||||||
|
+ boolean isCredentialsNonExpired()
|
||||||
|
+ boolean isEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GrantedAuthoritiesMapper {
|
||||||
|
+ Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GrantedAuthority {
|
||||||
|
+ String getAuthority()
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleGrantedAuthority {
|
||||||
|
- String role
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpringCacheBasedUserCache
|
||||||
|
class UsernamePasswordAuthenticationToken {
|
||||||
|
- Object principal
|
||||||
|
- Object credentials
|
||||||
|
}
|
||||||
|
abstract AbstractAuthenticationToken {
|
||||||
|
- Collection<GrantedAuthority> authorities
|
||||||
|
- Object details
|
||||||
|
- boolean authenticated
|
||||||
|
}
|
||||||
|
interface Authentication
|
||||||
|
interface CredentialsContainer {
|
||||||
|
+ void eraseCredentials()
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthenticationManager <|.. ProviderManager
|
||||||
|
ProviderManager +-- NullEventPublisher
|
||||||
|
NullEventPublisher ..|> AuthenticationEventPublisher
|
||||||
|
AuthenticationProvider "1..*" --* "1" ProviderManager
|
||||||
|
AbstractUserDetailsAuthenticationProvider ..|> AuthenticationProvider
|
||||||
|
DefaultPreAuthenticationChecks --+ AbstractUserDetailsAuthenticationProvider
|
||||||
|
DefaultPostAuthenticationChecks --+ AbstractUserDetailsAuthenticationProvider
|
||||||
|
UserDetailsChecker <|.. DefaultPreAuthenticationChecks
|
||||||
|
UserDetailsChecker <|.. DefaultPostAuthenticationChecks
|
||||||
|
UserCache --* AbstractUserDetailsAuthenticationProvider
|
||||||
|
UserDetails --* AbstractUserDetailsAuthenticationProvider
|
||||||
|
UserDetails --* UserDetailsChecker
|
||||||
|
UserDetails --* UserCache
|
||||||
|
AbstractUserDetailsAuthenticationProvider *--- GrantedAuthoritiesMapper
|
||||||
|
GrantedAuthoritiesMapper *-- GrantedAuthority
|
||||||
|
GrantedAuthority <|.. SimpleGrantedAuthority
|
||||||
|
UserCache <|.. SpringCacheBasedUserCache
|
||||||
|
UsernamePasswordAuthenticationToken --* AbstractUserDetailsAuthenticationProvider
|
||||||
|
AbstractAuthenticationToken <|-- UsernamePasswordAuthenticationToken
|
||||||
|
Authentication <|.. AbstractAuthenticationToken
|
||||||
|
CredentialsContainer <|.. AbstractAuthenticationToken
|
||||||
|
@enduml
|
90
drawings/spring-security-cotnextholder.puml
Normal file
90
drawings/spring-security-cotnextholder.puml
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
@startuml
|
||||||
|
skinparam Shadowing false
|
||||||
|
skinparam class {
|
||||||
|
BackgroundColor White
|
||||||
|
}
|
||||||
|
hide empty members
|
||||||
|
|
||||||
|
package org.springframework.security.core {
|
||||||
|
package context {
|
||||||
|
class SecurityContextHolder {
|
||||||
|
-{static} SecurityContextHolderStrategy strategy
|
||||||
|
-{static} int initilizeCount
|
||||||
|
-{static} void initilize()
|
||||||
|
+{static} void clearContext()
|
||||||
|
+{static} SecurityContext getContext()
|
||||||
|
+{static} int getInitilizeCount()
|
||||||
|
+{static} void setContext(SecurityContext context)
|
||||||
|
+{static} void setStrategyName(String strategyName)
|
||||||
|
+{static} SecurityContextHolderStrategy getContextHolderStrategy()
|
||||||
|
+{static} SecurityContext createEmptyContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecurityContextHolderStrategy {
|
||||||
|
+ void clearContext()
|
||||||
|
+ SecurityContext getContext()
|
||||||
|
+ void setContext(SecurityContext context)
|
||||||
|
+ SecurityContext createEmptyContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThreadLocalSecurityContextHolderStrategy {
|
||||||
|
-{static} ThreadLocal<SecurityContext> contextHolder
|
||||||
|
}
|
||||||
|
|
||||||
|
class GlobalSecurityContextHolderStrategy {
|
||||||
|
-{static} SecurityContext contextHolder
|
||||||
|
}
|
||||||
|
|
||||||
|
class InheritableThreadLocalSecurityContextHolderStrategy {
|
||||||
|
-{static} ThreadLocal<SecurityContext> contextHolder
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReactiveSecurityContextHolder {
|
||||||
|
+{static} Mono<SecurityContext> getContext()
|
||||||
|
-{static} boolean hasSecurityContext(Context context)
|
||||||
|
-{static} Mono<SecurityContext> getSecurityContext(Context context)
|
||||||
|
+{static} Function<Context, Context> clearContext()
|
||||||
|
+{static} Context withSecurityContext(Mono<? extends SecurityContext> securityContext)
|
||||||
|
+{static} Context withAuthentication(Authentication authntication)
|
||||||
|
}
|
||||||
|
|
||||||
|
class SecurityContext {
|
||||||
|
+ Authentication getAuthentication()
|
||||||
|
+ void setAuthentication(Authentication authentication)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Authentication {
|
||||||
|
+ Collection<? extends GrantedAuthority> getAuthorities()
|
||||||
|
+ Object getCredentials()
|
||||||
|
+ Object getDetails()
|
||||||
|
+ Object getPrincipal()
|
||||||
|
+ boolean isAuthticated()
|
||||||
|
+ setAuthenticated(boolean isAuthenticated)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GrantedAuthority {
|
||||||
|
+ String getAuthority()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
package java.security {
|
||||||
|
interface Principal {
|
||||||
|
+ String getName()
|
||||||
|
+ boolean implies(Subject subject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SecurityContextHolderStrategy --* SecurityContextHolder
|
||||||
|
ThreadLocalSecurityContextHolderStrategy ..|> SecurityContextHolderStrategy
|
||||||
|
GlobalSecurityContextHolderStrategy ..|> SecurityContextHolderStrategy
|
||||||
|
InheritableThreadLocalSecurityContextHolderStrategy ...|> SecurityContextHolderStrategy
|
||||||
|
SecurityContext --* SecurityContextHolderStrategy
|
||||||
|
SecurityContext -* ReactiveSecurityContextHolder
|
||||||
|
SecurityContext --* ThreadLocalSecurityContextHolderStrategy
|
||||||
|
SecurityContext --* InheritableThreadLocalSecurityContextHolderStrategy
|
||||||
|
SecurityContext --* GlobalSecurityContextHolderStrategy
|
||||||
|
Authentication --* SecurityContext
|
||||||
|
GrantedAuthority -* Authentication
|
||||||
|
Authentication -|> Principal
|
||||||
|
@enduml
|
71
drawings/spring-security-daoauthneticationprovider.puml
Normal file
71
drawings/spring-security-daoauthneticationprovider.puml
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
@startuml
|
||||||
|
skinparam Shadowing false
|
||||||
|
skinparam class {
|
||||||
|
BackgroundColor White
|
||||||
|
}
|
||||||
|
hide empty members
|
||||||
|
|
||||||
|
abstract AbstractUserDetailsAuthenticationProvider
|
||||||
|
class UserDetails
|
||||||
|
|
||||||
|
class DaoAuthenticationProvider {
|
||||||
|
- PasswordEncoder passwordEncoder
|
||||||
|
- String userNotFoundEncodedPassword
|
||||||
|
- UserDetailsService userDetailsService
|
||||||
|
- UserDetailsPasswordService userDetailsPasswordService
|
||||||
|
- void prepareTimingAttackProtection()
|
||||||
|
- void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserDetailsService {
|
||||||
|
+ UserDetails loadUserByUsername(String username)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserDetailsPasswordService {
|
||||||
|
+ UserDetails update(UserDetails user, String password)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PasswordEncoder {
|
||||||
|
+ String encode(CharSequence rawPassword)
|
||||||
|
+ boolean matches(CharSequence rawPassword, String encodedPassword)
|
||||||
|
+ boolean upgradeEncoding(String rawPassword)
|
||||||
|
}
|
||||||
|
class UsernamePasswordAuthenticationToken
|
||||||
|
|
||||||
|
abstract AbstractPasswordEncoder {
|
||||||
|
# byte[] encode(CharSequence rawPassword, byte[] salt)
|
||||||
|
# byte[] encodeAndConcatenate(CharSequence rawPassword, byte[] salt)
|
||||||
|
# {static} boolean matches(byte[] expected, byte[] actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
class DelegatingPasswordEncoder {
|
||||||
|
- {static} String PREFIX
|
||||||
|
- {static} String SUFFIX
|
||||||
|
- String idForEncode
|
||||||
|
- PasswordEncoder passwordEncoderForEncode
|
||||||
|
- Map<String, PasswordEncoder> idToPasswordEncoder
|
||||||
|
- PasswordEncoder defaultPasswordEncoderForMatches
|
||||||
|
+ DelegatingPasswordEncoder(String idForEncode, Map<String, PasswordEncoder> idToPasswordEncoder)
|
||||||
|
+ void setDefaultPasswordEncoderForMatches(PasswordEncoder defaultPasswordEncoderForMatches)
|
||||||
|
- String extractId(String prefixEncodedPassword)
|
||||||
|
- String extractEncodedPassword(String prefixEncodedPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnmappedIdPasswordEncoder
|
||||||
|
class BCryptPasswordEncoder
|
||||||
|
class Pbkdf2PasswordEncoder
|
||||||
|
|
||||||
|
DaoAuthenticationProvider --|> AbstractUserDetailsAuthenticationProvider
|
||||||
|
UserDetailsService --* DaoAuthenticationProvider
|
||||||
|
UserDetailsPasswordService --* DaoAuthenticationProvider
|
||||||
|
UsernamePasswordAuthenticationToken --* DaoAuthenticationProvider
|
||||||
|
PasswordEncoder ---* DaoAuthenticationProvider
|
||||||
|
UserDetails --* UserDetailsService
|
||||||
|
UserDetails --* UserDetailsPasswordService
|
||||||
|
AbstractPasswordEncoder ..|> PasswordEncoder
|
||||||
|
DelegatingPasswordEncoder ..|> PasswordEncoder
|
||||||
|
DelegatingPasswordEncoder +-- UnmappedIdPasswordEncoder
|
||||||
|
UnmappedIdPasswordEncoder ..|> PasswordEncoder
|
||||||
|
BCryptPasswordEncoder ..|> PasswordEncoder
|
||||||
|
Pbkdf2PasswordEncoder ..|> PasswordEncoder
|
||||||
|
@enduml
|
34
drawings/spring-security-servlet-flow.puml
Normal file
34
drawings/spring-security-servlet-flow.puml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
@startdot spring-security-servlet-flow
|
||||||
|
digraph servlet {
|
||||||
|
rankdir=TB
|
||||||
|
edge [color="#A60738"]
|
||||||
|
node [color="#A60738"]
|
||||||
|
|
||||||
|
client [shape=box, label="客户端"]
|
||||||
|
servlet [shape=box, label="Servlet"]
|
||||||
|
tokenStorage [shape=box, label="令牌缓存"]
|
||||||
|
|
||||||
|
{ rank=same; tokenStorage; RememberMeServices }
|
||||||
|
|
||||||
|
client -> FilterChain [label="原始请求"]
|
||||||
|
FilterChain -> SecurityFilterChain [label="经过中转的请求"]
|
||||||
|
SecurityFilterChain -> UsernamePasswordAuthenticationProviderFilter [label="携带有用户名和密码的请求"]
|
||||||
|
UsernamePasswordAuthenticationProviderFilter -> AuthenticationManager [label="UsernamePasswordAuthenticationToken"]
|
||||||
|
AuthenticationManager -> SecurityContext [label="认证后的Authentication"]
|
||||||
|
SecurityFilterChain -> BearerTokenAuthenticationFilter [label="携带有Authorization头的请求"]
|
||||||
|
BearerTokenAuthenticationFilter -> AuthenticationManager [label="BearerTokenAuthenticationToken"]
|
||||||
|
AuthenticationManager -> DaoAuthenticationProvider [label="UsernamePasswordAuthenticationToken"]
|
||||||
|
DaoAuthenticationProvider -> UserDetailsService [label="UserDetails"]
|
||||||
|
UserDetailsService -> DaoAuthenticationProvider [label="认证后的UserDetails"]
|
||||||
|
DaoAuthenticationProvider -> PasswordEncoder [label="用户认证密码"]
|
||||||
|
PasswordEncoder -> DaoAuthenticationProvider [label="经过加密的密码"]
|
||||||
|
DaoAuthenticationProvider -> SecurityContext [label="认证后的Authentication"]
|
||||||
|
SecurityFilterChain -> RememberMeAuthenticationFilter [label="携带RememberMe认证的请求"]
|
||||||
|
RememberMeAuthenticationFilter -> RememberMeServices [label="RememberMeAuthenticationToken"]
|
||||||
|
RememberMeServices -> tokenStorage [label="认证令牌信息"]
|
||||||
|
RememberMeServices -> SecurityContext [label="认证后的Authentication"]
|
||||||
|
SecurityFilterChain -> AnonymousAuthenticationFilter [label="不携带任何认证信息请求"]
|
||||||
|
AnonymousAuthenticationFilter -> SecurityContext [label="匿名Authentication"]
|
||||||
|
SecurityContext -> servlet [label="已经加入认证信息的请求"]
|
||||||
|
}
|
||||||
|
@enddot
|
26
drawings/spring-security-webflux-flow.puml
Normal file
26
drawings/spring-security-webflux-flow.puml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
@startdot spring-security-webflux-flow
|
||||||
|
digraph webfluxFlow {
|
||||||
|
rankdir=TB
|
||||||
|
edge [color="#A60738"]
|
||||||
|
node [color="#A60738"]
|
||||||
|
|
||||||
|
client [shape=box, label="客户端"]
|
||||||
|
endpoint [shape=box, label="处理端点"]
|
||||||
|
' tokenStorage [shape=box, label="令牌缓存"]
|
||||||
|
|
||||||
|
client -> SecurityFilterChain [label="HTTP请求"]
|
||||||
|
SecurityFilterChain -> AnonymousAuthenticationWebFilter [label="ServerWebExchange"]
|
||||||
|
AnonymousAuthenticationWebFilter -> SecurityContext [label="匿名Authentication"]
|
||||||
|
SecurityContext -> endpoint
|
||||||
|
SecurityFilterChain -> AuthenticationWebFilter [label="ServerWebExchange"]
|
||||||
|
AuthenticationWebFilter -> ReactivePreAuthenticatedAuthenticationManager [label="认证前的Authentication"]
|
||||||
|
ReactivePreAuthenticatedAuthenticationManager -> ReactiveUserDetailsService [label="用户认证信息"]
|
||||||
|
ReactiveUserDetailsService -> ReactivePreAuthenticatedAuthenticationManager [label="PreAuthenticatedAuthenticationToken"]
|
||||||
|
ReactivePreAuthenticatedAuthenticationManager -> AuthenticationWebFilter [label="PreAuthenticatedAuthenticationToken"]
|
||||||
|
AuthenticationWebFilter -> SecurityContext [label="认证后的Authentication"]
|
||||||
|
AuthenticationWebFilter -> JwtReactiveAuthenticationManager [label="认证前的Authentication"]
|
||||||
|
JwtReactiveAuthenticationManager -> AuthenticationWebFilter [label="BearerTokenAuthenticationToken"]
|
||||||
|
JwtReactiveAuthenticationManager -> JwtAuthenticationConverter [label="Jwt"]
|
||||||
|
JwtAuthenticationConverter -> JwtReactiveAuthenticationManager [label="JwtAuthenticationToken"]
|
||||||
|
}
|
||||||
|
@enddot
|
140
source/_posts/spring-security-basic.md
Normal file
140
source/_posts/spring-security-basic.md
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
---
|
||||||
|
title: Spring Security基础
|
||||||
|
tags:
|
||||||
|
- Java
|
||||||
|
- Spring
|
||||||
|
- Spring Security
|
||||||
|
- 安全认证
|
||||||
|
categories:
|
||||||
|
- - JVM
|
||||||
|
- Spring
|
||||||
|
keywords: 'Spring,Spring Security,UserDetails,SecurityContext'
|
||||||
|
date: 2021-07-29 21:59:41
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
Spring Security 是 Spring 框架中的安全框架,整个 Spring Security 在学习起来都是比较复杂的。这也是因为 Spring Security 在设计上所需要的组件比较多,所以比较难以理解。本文将尝试通过组成 Spring Securit 功能的常用功能组件以图的形式进行说明,以方便对于 Spring Security 能有一个比较清楚直观的理解。<!-- more -->
|
||||||
|
|
||||||
|
本篇关于 Spring Security 的文章主要由三部分组成,分别是:
|
||||||
|
|
||||||
|
1. {% post_link spring-security-basic %}
|
||||||
|
1. {% post_link spring-security-webmvc %}
|
||||||
|
1. {% post_link spring-security-webflux %}
|
||||||
|
|
||||||
|
## 基础组成
|
||||||
|
|
||||||
|
### SecurityContextHolder
|
||||||
|
|
||||||
|
在 Spring Security 中,`SecurityContextHolder`是 Spring Security 记录认证结果的核心。所有已经被认证过的用户都将被保存在`SecurityContextHolder`中。每个`SecurityContextHolder`实例中会利用一个`SecurityContextHolderStrategy`实例来保存已经完成验证的`SecurityContext`实例。
|
||||||
|
|
||||||
|
所以,在 Spring Security 中,每一个非空的`SecurityContextHolder`就代表着一个已经被认证过的用户,而且在 Spring Security 中,非空的`SecurityContextHolder`实例也常常被用来表示当前已经被认证过的用户。
|
||||||
|
|
||||||
|
以下是`SecurityContextHolder`系列接口的构成示意图。
|
||||||
|
|
||||||
|
{% oss_image spring-security/spring-security-cotnextholder.svg "SecurityContextHolder类结构图" %}
|
||||||
|
|
||||||
|
从这张图上可以看出,`SecurityContextHolder`中主要是利用其中的`SecurityContextHolderStrategy`实例来管理其中持有的`SecurityContext`实例。但是在实际使用时,我们并不需要直接调用`SecurityContextHolderStrategy`实例,只需要利用`SecurityContextHolder`来完成操作即可。
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
如果想要在`SecurityContextHolder`中使用不同的策略实例,可以在配置文件中设定`spring.security.strategy`的值,这一配置项可以取以下三个值:`MODE_THREADLOCAL`、`MODE_INHERITABLETHREADLOCAL`、`MODE_GLOBAL`。在没有设置所需要使用的策略时,会默认采用`MODE_THREADLOCAL`。
|
||||||
|
|
||||||
|
### SpringContext
|
||||||
|
|
||||||
|
`SpringContext`类就比较简单了,根据上图描述,`SpringContext`里就是包含了一个`Authentication`接口实例。
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
`Authentication`接口是Spring Security中的认证功能核心,在Spring Security中主要执行以下两个功能:
|
||||||
|
|
||||||
|
1. 作为`AuthenticationManager`的输入数据来对用户进行认证。
|
||||||
|
1. 代表一个目前已经被认证的用户,在这种情况下,`Authentication`实例可以从`SecurityContext`中获得。
|
||||||
|
|
||||||
|
`Authentication`中通常会包含三种内容:Principal、Credentials、Authorities。虽然在上图中,Principal和Credentials都是`Object`类型的,但Principal通常都是以`UserDetails`接口实例的形式出现,而Credentials通常都是字符串。Authorities在上图中表示是一组`GrantedAuthority`实例,但是大部分情况下都是采用`SimpleGrantedAuthority`类包装的字符串组成Authorites集合。
|
||||||
|
|
||||||
|
### AuthenticationManager
|
||||||
|
|
||||||
|
`AuthenticationManager`在Spring Security中定义了如何执行用户身份验证,经过`AuthenticationManager`的执行以后,Spring Security即可以向`SecurityContextHolder`中写入被返回的验证信息。
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
`AuthenticationManager`通常会被应用成一个Servlet Filter,而这也是Spring Web MVC基于Servlet的处理流程。
|
||||||
|
|
||||||
|
由于`AuthenticationManager`只是一个接口,所以在实际使用时通常都使用`ProviderManager`类来实现其所定义的功能。常用的基于`AuthenticationManager`接口的类结构图如下。
|
||||||
|
|
||||||
|
{% oss_image spring-security/spring-secrutiy-authentication-manager.svg "AuthenticationManager类结构图" %}
|
||||||
|
|
||||||
|
从这张图上可以看出来,平时在使用`ProviderManager`的时候,实际上是在构建认证所需要的`AuthenticationProvider`。Spring Security提供了多个实现了`AuthenticationProvider`接口的抽象类,例如`AbstractUserDetailsAuthenticationProvider`,这些抽象类中实现了很多常用的功能,如果需要实现一个自定义`AuthenticationProvider`,可以直接继承这些抽象类。Spring Security中也是基于这些抽象类提供了许多常见的认证场景支持。这些常用的认证类主要有以下几个。
|
||||||
|
|
||||||
|
1. `DaoAuthenticationProvider`,提供基于用户名和密码的认证。
|
||||||
|
1. `JwtAuthenticationProvider`,提供基于JWT的认证。
|
||||||
|
1. `AnonymousAuthenticationProvider`,提供基于`AnonymousAuthenticationToken`的匿名用户认证。
|
||||||
|
1. `JaasAuthenticationProvider`,提供基于Java认证与授权的认证。
|
||||||
|
1. `RemoteAuthenticationProvider`,提供远程认证。
|
||||||
|
1. `LdapAuthenticationProvider`,提供基于LDAP的认证。
|
||||||
|
1. `OAuth2AuthenticationCodeAuthenticationProvider`,提供基于授权码的OAuth 2.0认证。
|
||||||
|
1. `OAuth2LoginAuthenticationProvider`,提供基于登录的OAuth 2.0认证。
|
||||||
|
1. `OpenIDAuthenticationProvider`,提供基于OpenID授权的认证。
|
||||||
|
1. `PreAuthenticatedAuthenticationProvider`,提供基于预认证的授权认证。
|
||||||
|
1. `CasAuthenticationProvider`,提供基于JA-SIG中央认证服务的授权认证。
|
||||||
|
1. `OpaqueTokenAuthenticationProvider`,提供基于不透明令牌的授权认证。
|
||||||
|
1. `JwtAuthenticationProvider`,提供基于JWT的授权认证。
|
||||||
|
|
||||||
|
### DaoAuthenticationProvider
|
||||||
|
|
||||||
|
`DaoAuthenticationProvider`是Spring Security中最常用的Authentication Provider,因为大部分认证场景都是基于用户名和密码的。`DaoAuthenticationProvider`进行认证功能的核心就是一个`UserDetailsService`实例,通过`UserDetailsService`可以完成用户提供的用户名和密码的验证,并且可以返回一个可供`Authentication`保存用户信息的`UserDetails`。
|
||||||
|
|
||||||
|
以下是`DaoAuthenticationProvider`的类结构图,在构建基于用户名和密码的认证过程中参考使用。
|
||||||
|
|
||||||
|
{% oss_image spring-security/spring-security-daoauthneticationprovider.svg DaoAuthenticationProvider类结构图 %}
|
||||||
|
|
||||||
|
### AbstractAuthenticationProcessingFilter
|
||||||
|
|
||||||
|
`AbstractAuthenticationProcessingFilter`继承了`GenericFilterBean`,是Spring Servlet应用中Security相关过滤器定义的抽象类。基于Servlet的Web应用中,一个请求在到达负责响应的Controller Bean之前,需要经过数层过滤器的处理。`AbstractAuthenticationProcessingFilter`所执行的功能就是把Spring Security的认证与授权功能以过滤器的形式插入到Web请求的处理流程之中。
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
在Spring Security的官方文档中,对于过滤器的使用还提到了`DelegatingFilterProxy`和`FilterChainProxy`,这两个代理类主要是用于在Servlet处理流程中插入Filter组合的,在绝大多数情况下都不需要手动控制。在使用过程中一般只需要定义所需要使用的Filter即可。
|
||||||
|
|
||||||
|
对于`SecurityFilterChain`在整个Servlet请求处理流程中插入的Filter的先后顺序,Spring Security官方文档是给了一个[列表](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#servlet-security-filters)的,可以直接参考使用。我们在日常使用过程中所需要关注的Filter主要有以下几个(按调用顺序排列,不一定全都使用)。
|
||||||
|
|
||||||
|
1. `CorsFilter`
|
||||||
|
1. `CsrfFilter`
|
||||||
|
1. `LogoutFilter`
|
||||||
|
1. `OAuth2AuthorizationRequestRedirectFilter`
|
||||||
|
1. `OAuth2LoginAuthenticationFilter`
|
||||||
|
1. `UsernamePasswordAuthenticationFilter`
|
||||||
|
1. `OpenIDAuthenticationFilter`
|
||||||
|
1. `BearerTokenAuthenticationFilter`
|
||||||
|
1. `RememberMeAuthenticationFilter`
|
||||||
|
1. `AnonymousAuthenticationFilter`
|
||||||
|
1. `OAuth2AuthorizationCodeGrantFilter`
|
||||||
|
1. `SessionManagementFilter`
|
||||||
|
1. `ExceptionTranslationFilter`
|
||||||
|
|
||||||
|
#### UsernamePasswordAuthenticationFilter
|
||||||
|
|
||||||
|
以`UsernamePasswordAuthenticationFilter`为例,它会将请求传入的用户名和密码整合放入`UsernamePasswordAuthenticationToken`中,这是一个实现了`Authentication`接口的类,主要用途就是存放用户认证信息。之后,`UsernamePasswordAuthenticaitonToken`实例就会被放入`AuthenticationManager`实例中进行认证。
|
||||||
|
|
||||||
|
所以在认证过程中所获取的`Authentication`接口实例,一般都是`UsernamePasswordAuthenticationToken`类的实例。
|
||||||
|
|
||||||
|
#### RememberMeAuthenticationFilter
|
||||||
|
|
||||||
|
`RememberMeAuthenticationFilter`可以主要用来提供已经完成认证的用户自动登录功能的过滤器,通过定义一个`RememberMeServices`接口或者`AbstractRememberMeServices`抽象类的实例,可以利用其中的`loginSuccess()`方法生成一个针对于已经完成认证的用户的记录,这种记录可以是Token、Cookie或者其他任何形式。所生成的用户记录可以在下一次请求的`autoLogin()`方法中使用,并在请求中恢复认证记录。
|
||||||
|
|
||||||
|
#### BearerTokenAuthenticationFilter
|
||||||
|
|
||||||
|
`BearerTokenAuthenticaitonFilter`的主要功能就是解析HTTP请求头中的`Authorization`,并将其中所携带的Token内容解析出来,形成一个`BearerTokenAuthenticationToken`实例,然后放入`AuthenticationManager`中进行认证,最后将认证结果放入`SecurityContextHolder`中。这里出现的`BearerTokenAuthenticationToken`也是一个`AbstractAuthenticationToken`抽象类的子类,其中也包含了认证所需要使用的用户名、认证资料等。
|
||||||
|
|
||||||
|
## Spring Web MVC中的认证流程
|
||||||
|
|
||||||
|
Spring Web MVC中主要是依赖于Servlet Filter组成的管道来对HTTP请求中携带的认证消息进行处理。下面借用一个伪数据流图来简单示意一下在一次Web请求中认证信息的处理过程。
|
||||||
|
|
||||||
|
{% oss_image spring-security/spring-security-servlet-flow.svg "Spring Web MVC认证流程示意" %}
|
||||||
|
|
||||||
|
从这个图上可以看出来,在Spring Web MVC中,这些实现了`javax.servlet.Filter`的认证过滤器才是才是真正启动认证过程执行的起点。而我们在使用时大多只需要为它们提供它们所依赖的工作实例即可,例如`UserDetailsService`、`PasswordEncoder`等。
|
||||||
|
|
||||||
|
## Spring WebFlux中的认证流程
|
||||||
|
|
||||||
|
Spring WebFlux中的依赖的是WebFilter组成的过滤器管道来对HTTP请求中携带的认证消息进行处理。这里同样借用一个伪数据流图来进行简单的示意。
|
||||||
|
|
||||||
|
{% oss_image spring-security/spring-security-webflux-flow.svg "Spring WebFlux认证流程示意" %}
|
||||||
|
|
||||||
|
Spring WebFlux中的认证流程和参与组件要比Spring Web MVC少很多。从上图可以看出来,启动认证过程的起点依旧是实现了`WebFilter`接口的过滤器,但是不同的认证过滤器开始使用不同的`AuthenticationManager`实例。但是整个流程中不变的是,所有已经完成认证的结果还都将保存到`SecurityContext`实例中。
|
Loading…
Reference in New Issue
Block a user