1.3 Authentication
Spring Security为我们提供了一个专门的org.springframework.security.core.Authentication
接口来代表认证;它最常用的实现类有UsernamePasswordAuthenticationToken
。
一旦请求被认证后,Authentication
对象就会自动存储在由SecurityContextHolder
管理的SecurityContext
中。
认证的原理通过下面类的处理顺序来进行的:
-
FilterChainProxy
:Servlet过滤器(Filter
)springSecurityFilterChain
实际类型是FilterChainProxy
,它可能包含多个过滤器链(DefaultSecurityFilterChain
),每个过滤器链包含多个过滤器。特定的过滤器会将请求中的认证信息(如用户名、密码)构造成Authentication
对象交由AuthenticationManager
的authenticate
方法处理。主要的过滤器有:UsernamePasswordAuthenticationFilter
:使用表单(用户名、密码)提交进行认证信息,构造的Authentication
对象类型为UsernamePasswordAuthenticationToken
;并调用AuthenticationManager
的authenticate
来进行认证操作。BasicAuthenticationFilter
:使用HTTP请求的基础授权头提交认证信息,同样构造的Authentication
对象的类型为UsernamePasswordAuthenticationToken
;并调用AuthenticationManager
的authenticate
来进行认证操作。ExceptionTranslationFilter
:处理过滤器链中的异常AuthenticationException
:认证异常,返回401
状态码AccessDeniedException
:授权异常,返回403
状态码
FilterSecurityInterceptor
:它是AbstractSecurityInterceptor
的子类,当认证成功后,再使用AccessDecisionManager
对Web路径资源(web URI)进行授权操作。
-
AuthenticationManager
:AuthenticationManager
接口的实现为ProviderManager
,我们使用AuthenticationManagerBuilder
来定制构建AuthenticationManager
-
ProviderManager
:ProviderManager
通过它authenticate
方法将认证交给了一组顺序的AuthenticationProvider
来完成认证。 -
AuthenticationProvider
:AuthenticationProvider
接口包含两个方法:supports
:是否支持认证安全过滤器缓解构造的Authentication
;authenticate
:对Authentication
进行认证,若认证通过返回Authentication
,若不通过则抛出异常。
-
DaoAuthenticationProvider
:DaoAuthenticationProvider
是AuthenticationProvider
接口的实现,他支持认证的Authentication
类型为UsernamePasswordAuthenticationToken
。它在认证中主要用到了下面三个部分:UserDetailsService
:从指定的位置(如数据库)获得用户信息;通过比较用户信息和Authentication
(UsernamePasswordAuthenticationToken
)中的用户名和密码信息,若认证通过则构建新的Authentication
(UsernamePasswordAuthenticationToken
),包含用户的权限信息。PasswordEncoder
:使用PasswordEncoder
将请求传来的明文密码和存储的编码后的密码进行匹配比较。
1.3.1 配置AuthenticationManager
我们可以重载WebSecurityConfigurerAdapter
类的方法,使用AuthenticationManagerBuilder
来配置AuthenticationManager
。
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//auth.
}
}
我们可以通过配置UserDetailsService
或AuthenticationProvider
定制认证。
1.3.2 UserDetailsService
本例定制一个UserDetailsService
通过Spring Data JPA从数据库中获取用户。
基本外部配置:
spring:
datasource:
url: jdbc:mysql://localhost:3306/first_db?useSSL=false
username: root
password: zzzzzz
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: true
hibernate:
ddl-auto: update
我们用户的实体:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class SysUser implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String realName;
@Column(unique = true)
private String username;
private String password;
public SysUser(String realName, String username, String password) {
this.realName = realName;
this.username = username;
this.password = password;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//1
return null;
}
@Override
public String getPassword() {
//2
return this.password;
}
@Override
public String getUsername() {
//3
return this.username;
}
@Override
public boolean isAccountNonExpired() {
//4
return true;
}
@Override
public boolean isAccountNonLocked() {
//5
return true;
}
@Override
public boolean isCredentialsNonExpired() {
//6
return true;
}
@Override
public boolean