Spring Security Core

核心组件

  • SecurityContextHolder,提供访问SecurityContext的
  • SecurityContext,存储Authentication 和可能的请求安全信息
  • Authentication,表示在Spring Security机制中的一个访问者
  • GrantedAuthority,反映访问者在应用范围的权限
  • UserDetails,提供必要的信息来构建Authentication对象,例如从应用的DAO 或者安全相关的数据源
  • UserDetailsService,通过传递基于字符串的用户名称(或者证书ID等)创建UserDetails

SecurityContextHolder

SecurityContextHolder是最基础的对象,我们用来存储表示当前应用安全的上下文信息,包含当前访问者的详情。默认情况,SecurityContextHolder使用ThreadLocal来存储这些详情,这意味着security context在同一个执行线程中是可以一直有效的,即使security context没有作为参数显示地传递到其他方法中。使用ThreadLocal比较安全,它会在当前访问者请求进程结束时被清理。

有些应用不适合使用一个ThreadLocal,它们可能使用别的方式处理线程,例如,一个Swing客户端可能要求JVM中所有线程使用同一个Security Context。SecurityContextHolder可以再启动的时候配置不同策略,来指定我们想如何存储上下文信息。例如一个单应用可能使用SecurityContextHolder.MODE_GLOBAL策略。其他应用可能要求线程从同一个secure thread继承,这时,可以设置为SecurityContextHolder.MODE_IHERITABLETHREADLOCAL。有两种方式来变默认的SecurityContextHolder.MODE_THREADLOCAL,一是设置系统属性,二是调用SecurityContextHolder的静态方法。大多数情况不需要改变默认的策略。

通过SecurityContextHolder我们可以获取当前访问者的信息,Spring Security使用一个Authentication对象来表示这些信息。我们不需要自己来创建这个Authentication对象,但是比较常见的是查询Authentication对象。例如:

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (principal instanceof UserDetails) {
	String username = ((UserDetails)principal).getUsername();
} else {
	String username = principal.toString();
}

UserDetailsService

我们可以从Authentication对象中获取访问者信息,访问者是一个Object,一般情况下,可以转换为UserDetailsUserDetails是Spring Security核心接口。它表示访问者,但也支持扩展,可以把UserDetails理解为我们自己用户数据与Spring Security所需的适配器。我们可以强转为我们自己的对象。

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserInfoRepository repository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<UserInfo> user =
                repository.findByUsername(username);

        return user.orElseThrow(() ->
                new UsernameNotFoundException("user does not exists"));
    }
}