Spring Security认证简单原理

413 阅读3分钟

Spring Security内部是通过一个过滤器链进行认证和授权的,在启动Spring Boot项目后可以通过断点查看过滤器链的属性:

截屏2022-07-20 上午12.48.41.png 可以在截图中看到,过滤器链被保存在 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 的认证操作。它包含两个方法:

  1. Authentication authenticate(Authentication authentication)

此方法是对 Authentication 认证的具体逻辑

  1. 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();
    }
}