Spring Security内部是通过一个过滤器链进行认证和授权的,在启动Spring Boot项目后可以通过断点查看过滤器链的属性:
可以在截图中看到,过滤器链被保存在 FilterChainProxy 对象里,类型为 DefaultSecurityFilterChain
Spring Security认证重要接口
Spring Security用户认证有三个重要的组件:
- Authentication
- AuthenticationProvider
- AuthenticationManager
Authentication
Authentication 接口是用户认证凭证,里面会存储用户相关信息,如果你选择不同的认证方式,就会有不同的认证凭证,比如:TOKEN、Basic等。UsernamePasswordAuthenticationToken是 Spring Security 提供的该接口的一个实现类,该类可以保存用户名和密码用于之后的用户认证
getPrincipal()方法返回被认证的主体,可以是用户名或者用户ID或者用户信息对象,具体的值可以根据凭证类型返回
getCredentials()方法返回能够认证对象的信息,可以是用户密码
getAuthorities()方法返回用户权限,用于授权
setAuthenticated()方法设置认证是否通过
isAuthenticated()方法返回认证是否通过
AuthenticationProvider
AuthenticationProvider 接口完成对 Autnentication 的认证操作。它包含两个方法:
- Authentication authenticate(Authentication authentication)
此方法是对 Authentication 认证的具体逻辑
- boolean supports(Class<?> authentication)
此方法是确定支持的 Authentication
Spring Security 提供了一些默认的实现,比如 DaoAuthenticationProvider。DaoAuthenticationProvider 能够认证的是 UsernamePasswordAuthenticationToken 类型的凭证。需要注意的是 DaoAuthenticationProvider 需要一个 PasswordEncoder 实例和一个 UserDetailsService 实例。
PasswordEncoder 用来对比前端传输的明文密码和后端持久化存储的加密密码是否匹配
UserDetailsService 该接口只有一个 loadUserByUsername(String username)方法,根据用户名获取用户信息
AuthenticationManager
AuthenticationManagement 是认证管理器,其主要是用来管理多个 AuthenticationProvider。该接口只有 authentication authenticate(Authentication authentication) 方法,是用户认证的入口
Spring Security 提供了 ProviderManager,ProviderManager 有一个 providers 属性存储了 AuthenticationProvider 集合,其认证方法主要就是遍历 providers 进行处理
简单认证流程
使用token认证方式
登录接口不需要认证即可访问,登录成功后会返回给用户一个token,之后每次请求都需要在请求头中携带该token。
后端对token进行认证首先需要定义一个token认证过滤器,在该过滤器中获取到token的值并且构建Token Authentication,然后使用Token AuthenticationProvider 对token进行校验,校验通过则设置认证通过,构建用户信息和权限信息到 Token Authentication,并返回
Spring Security 简单配置
Spring Security 配置主要是通过继承 WebSecurityConfigurerAdapter
@Configuration
public class ZuulSecurityConfig extends WebSecurityConfigurerAdapter {
private final DemoAuthenticationProvider demoAuthenticationProvider;
@Autowired
public ZuulSecurityConfig(DemoAuthenticationProvider demoAuthenticationProvider) {
this.demoAuthenticationProvider = demoAuthenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//添加AuthenticationProvider
auth.authenticationProvider(demoAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
//登录接口不需要认证即可访问
.antMatchers(
"/**/api/user/login/v1",
"/favicon.ico")
.permitAll()
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//添加过滤器
http.addFilterBefore(new DemoAuthenticationFilter(authenticationManagerBean()),
UsernamePasswordAuthenticationFilter.class);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/**/api/user/login/v1",
"/**/favicon.ico");
}
/**
* 暴露 AuthenticationManager
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}