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
,一般情况下,可以转换为UserDetails
。UserDetails
是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"));
}
}