转载

Spring Security 认证流程梳理

前面的简单的认证流程中,是可以将一些东西抽象出来作为一个单独的实体,这些实体都可以在 Spring Security 中找到相应的对象,包括:

  1. 用户输入的账号密码等信息,这些东西其实就是用户的认证信息,对应到 Spring Security 中的话就是 Authentication 对象,只不过,Spring Security 中的 Authentication 对象除了保存用户的认证信息以外,还可以用来保存用户认证成功后从数据库中拿到的用户的详细信息。

    public interface Authentication extends Principal, Serializable {
      Collection<? extends GrantedAuthority> getAuthorities();  // 用户权限
      Object getCredentials();                                  // 用户认证信息
      Object getDetails();                                      // 用户详细信息
      Object getPrincipal();                                    // 用户身份信息
      boolean isAuthenticated();                                // 当前 Authentication 是否已认证
      void setAuthenticated(boolean isAuthenticated);
    }
  2. 只凭用户提供的认证信息往往是不足以用来判断该用户是否合法的,因此,我们通常还需要某种手段来获取保存在服务端的用户信息,同时,也需要某种手段来保存用户信息,这些对应到 Spring Security 中的话就是 UserDetailsServiceUserDetails 这两个对象。

    public interface UserDetailsService {
      UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
    }
    
    public interface UserDetails extends Serializable {
      Collection<? extends GrantedAuthority> getAuthorities();
      String getPassword();
      String getUsername();
      boolean isAccountNonExpired();
      boolean isAccountNonLocked();
      boolean isCredentialsNonExpired();
      boolean isEnabled();
    }
  3. 在拥有了用户提供的认证信息和保存在服务端的用户信息后,我们就需要通过某种方式来比较这两份信息,而这种来效验用户认证信息的对象对应到 Spring Security 中便是 AuthenticationManager 对象了。

    Authentication authenticate(Authentication authentication)throws AuthenticationException;

    而鉴于各种各样的用户认证信息和层出不穷的效验方式,Spring Security 提供了更易于我们扩展的接口 AuthenticationProviderProviderManager 这个默认的 AuthenticationManager 实现。使用时,我们往往就只需要实现 AuthenticationProvider 就足够了。

    public interface AuthenticationProvider {
      Authentication authenticate(Authentication authentication) throws AuthenticationException;
      boolean supports(Class<?> authentication);
    }

    可以看到,AuthenticationProvider 中的方法 authenticate 会返回一个 Authentication 对象,当通过认证后,这个对象往往会保存用户的详细信息。

  4. 当用户的认证信息通过效验后,我们往往还需要在服务端保存通过的认证信息或生成的令牌,这个保存通过的认证信息的对象在 Spring Security 中就是 SecurityContextSecurityContextHolder 这两个对象, SecurityContext 保存已通过认证的 Authentication 对象,SecurityContextHolder 保存 SecurityContext 到当前线程的上下文,方便我们的使用。

    public interface SecurityContext extends Serializable {
      Authentication getAuthentication();
      void setAuthentication(Authentication authentication);
    }
    
    public class SecurityContextHolder {
      public static SecurityContext getContext();
      public void SecurityContext setContext();
    }

    Spring Security 是基于 Filter 来实现的,而每个请求往往也会分配一个线程,因此,Spring Security 在请求到达具体的处理逻辑之前,就可以在 Filter 中完成用户信息的认证,生成 SecurityContext 方面后续的使用。

这里在附上一张来源于 Spring Security(一) —— Architecture Overview | 芋道源码 —— 纯源码解析博客 的一张图,很好的解释了上述对象之间的关系:

Spring Security 认证流程梳理

可以看到,虽然 Spring Security 看似很复杂,但是其核心思想和以前那种简单的认证流程依然是一样的。只不过,Spring Security 将其中的关键部分抽象了处理,又提供了相应的扩展接口。

我们在使用时,便可以实现自己的 UserDetailsService 和 UserDetails 来获取保存用户信息,实现自己的 Authentication 来保存特定的用户认证信息,实现自己的 AuthenticationProvider 使用自己的 UserDetailsService 和 Authentication 来对用户认证信息进行效验。

当然了,Spring Security 还存在更多的功能,但是,在对基本流程有了一定的理解后,后续的内容也就能够更加容易的进行学习了。

原文  https://rgb-24bit.github.io/blog/2019/spring-security-certification-process.html
正文到此结束
Loading...